Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sage
Path: blob/develop/src/sage_setup/autogen/interpreters/internal/specs/python.py
4089 views
1
# ****************************************************************************
2
# Copyright (C) 2009 Carl Witty <[email protected]>
3
# Copyright (C) 2015 Jeroen Demeyer <[email protected]>
4
#
5
# This program is free software: you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation, either version 2 of the License, or
8
# (at your option) any later version.
9
# https://www.gnu.org/licenses/
10
# ****************************************************************************
11
from .base import StackInterpreter
12
from ..instructions import (params_gen, instr_funcall_2args, instr_unary,
13
InstrSpec)
14
from ..memory import MemoryChunk
15
from ..storage import ty_python
16
from ..utils import je, reindent_lines as ri
17
18
19
class MemoryChunkPythonArguments(MemoryChunk):
20
r"""
21
A special-purpose memory chunk, for the generic Python-object based
22
interpreter. Rather than copy the arguments into an array allocated
23
in the wrapper, we use the PyTupleObject internals and pass the array
24
that's inside the argument tuple.
25
"""
26
27
def declare_class_members(self):
28
r"""
29
Return a string giving the declarations of the class members
30
in a wrapper class for this memory chunk.
31
32
EXAMPLES::
33
34
sage: from sage_setup.autogen.interpreters.internal import *
35
sage: from sage_setup.autogen.interpreters.internal.specs.python import *
36
sage: mc = MemoryChunkPythonArguments('args', ty_python)
37
"""
38
return " cdef int _n_%s\n" % self.name
39
40
def init_class_members(self):
41
r"""
42
Return a string to be put in the __init__ method of a wrapper
43
class using this memory chunk, to initialize the corresponding
44
class members.
45
46
EXAMPLES::
47
48
sage: from sage_setup.autogen.interpreters.internal import *
49
sage: from sage_setup.autogen.interpreters.internal.specs.python import *
50
sage: mc = MemoryChunkPythonArguments('args', ty_python)
51
sage: mc.init_class_members()
52
" count = args['args']\n self._n_args = count\n"
53
"""
54
return je(ri(8,
55
"""
56
count = args['{{ myself.name }}']
57
self._n_args = count
58
"""), myself=self)
59
60
def setup_args(self):
61
r"""
62
Handle the arguments of __call__. Nothing to do.
63
64
EXAMPLES::
65
66
sage: from sage_setup.autogen.interpreters.internal import *
67
sage: from sage_setup.autogen.interpreters.internal.specs.python import *
68
sage: mc = MemoryChunkPythonArguments('args', ty_python)
69
sage: mc.setup_args()
70
''
71
"""
72
return ''
73
74
def pass_argument(self):
75
r"""
76
Pass the innards of the argument tuple to the interpreter.
77
78
EXAMPLES::
79
80
sage: from sage_setup.autogen.interpreters.internal import *
81
sage: from sage_setup.autogen.interpreters.internal.specs.python import *
82
sage: mc = MemoryChunkPythonArguments('args', ty_python)
83
sage: mc.pass_argument()
84
'(<PyTupleObject*>args).ob_item'
85
"""
86
return "(<PyTupleObject*>args).ob_item"
87
88
89
class MemoryChunkPyConstant(MemoryChunk):
90
r"""
91
A special-purpose memory chunk, for holding a single Python constant
92
and passing it to the interpreter as a PyObject*.
93
"""
94
95
def __init__(self, name):
96
r"""
97
Initialize an instance of MemoryChunkPyConstant.
98
99
Always uses the type ty_python.
100
101
EXAMPLES::
102
103
sage: from sage_setup.autogen.interpreters.internal import *
104
sage: from sage_setup.autogen.interpreters.internal.specs.python import *
105
sage: mc = MemoryChunkPyConstant('domain')
106
sage: mc.name
107
'domain'
108
sage: mc.storage_type is ty_python
109
True
110
"""
111
super(MemoryChunkPyConstant, self).__init__(name, ty_python)
112
113
def declare_class_members(self):
114
r"""
115
Return a string giving the declarations of the class members
116
in a wrapper class for this memory chunk.
117
118
EXAMPLES::
119
120
sage: from sage_setup.autogen.interpreters.internal import *
121
sage: from sage_setup.autogen.interpreters.internal.specs.python import *
122
sage: mc = MemoryChunkPyConstant('domain')
123
sage: mc.declare_class_members()
124
' cdef object _domain\n'
125
"""
126
return je(ri(4,
127
"""
128
cdef object _{{ myself.name }}
129
"""), myself=self)
130
131
def init_class_members(self):
132
r"""
133
Return a string to be put in the __init__ method of a wrapper
134
class using this memory chunk, to initialize the corresponding
135
class members.
136
137
EXAMPLES::
138
139
sage: from sage_setup.autogen.interpreters.internal import *
140
sage: from sage_setup.autogen.interpreters.internal.specs.python import *
141
sage: mc = MemoryChunkPyConstant('domain')
142
sage: mc.init_class_members()
143
" self._domain = args['domain']\n"
144
"""
145
return je(ri(8,
146
"""
147
self._{{ myself.name }} = args['{{ myself.name }}']
148
"""), myself=self)
149
150
def declare_parameter(self):
151
r"""
152
Return the string to use to declare the interpreter parameter
153
corresponding to this memory chunk.
154
155
EXAMPLES::
156
157
sage: from sage_setup.autogen.interpreters.internal import *
158
sage: from sage_setup.autogen.interpreters.internal.specs.python import *
159
sage: mc = MemoryChunkPyConstant('domain')
160
sage: mc.declare_parameter()
161
'PyObject* domain'
162
"""
163
return 'PyObject* %s' % self.name
164
165
def pass_argument(self):
166
r"""
167
Return the string to pass the argument corresponding to this
168
memory chunk to the interpreter.
169
170
EXAMPLES::
171
172
sage: from sage_setup.autogen.interpreters.internal import *
173
sage: from sage_setup.autogen.interpreters.internal.specs.python import *
174
sage: mc = MemoryChunkPyConstant('domain')
175
sage: mc.pass_argument()
176
'<PyObject*>self._domain'
177
"""
178
return '<PyObject*>self._%s' % self.name
179
180
181
class PythonInterpreter(StackInterpreter):
182
r"""
183
A subclass of StackInterpreter, specifying an interpreter over
184
Python objects.
185
186
Let's discuss how the reference-counting works in Python-object
187
based interpreters.
188
189
There is a simple rule to remember: when executing the code
190
snippets, the input variables contain borrowed references;
191
you must fill in the output variables with references you own.
192
193
As an optimization, an instruction may set .handles_own_decref; in
194
that case, it must decref any input variables that came from the
195
stack. (Input variables that came from arguments/constants chunks
196
must NOT be decref'ed!) In addition, with .handles_own_decref, if
197
any of your input variables are arbitrary-count, then you must
198
NULL out these variables as you decref them. (Use Py_CLEAR to do
199
this, unless you understand the documentation of Py_CLEAR and why
200
it's different than Py_XDECREF followed by assigning NULL.)
201
202
Note that as a tiny optimization, the interpreter always assumes
203
(and ensures) that empty parts of the stack contain NULL, so
204
it doesn't bother to Py_XDECREF before it pushes onto the stack.
205
"""
206
207
name = 'py'
208
209
def __init__(self):
210
r"""
211
Initialize a PythonInterpreter.
212
213
EXAMPLES::
214
215
sage: from sage_setup.autogen.interpreters.internal import *
216
sage: from sage_setup.autogen.interpreters.internal.specs.python import *
217
sage: interp = PythonInterpreter()
218
sage: interp.name
219
'py'
220
sage: interp.mc_args
221
{MC:args}
222
sage: interp.chunks
223
[{MC:args}, {MC:constants}, {MC:stack}, {MC:code}]
224
sage: instrs = dict([(ins.name, ins) for ins in interp.instr_descs])
225
sage: instrs['add']
226
add: SS->S = 'o0 = PyNumber_Add(i0, i1);'
227
sage: instrs['py_call']
228
py_call: *->S = '\nPyObject *py_args...CREF(py_args);\n'
229
"""
230
231
super(PythonInterpreter, self).__init__(ty_python)
232
# StackInterpreter.__init__ gave us a MemoryChunkArguments.
233
# Override with MemoryChunkPythonArguments.
234
self.mc_args = MemoryChunkPythonArguments('args', ty_python)
235
self.chunks = [self.mc_args, self.mc_constants, self.mc_stack,
236
self.mc_code]
237
self.c_header = ri(0,
238
"""
239
#define CHECK(x) (x != NULL)
240
""")
241
242
self.pyx_header = ri(0,
243
"""\
244
from cpython.number cimport PyNumber_TrueDivide
245
""")
246
247
pg = params_gen(A=self.mc_args, C=self.mc_constants, D=self.mc_code,
248
S=self.mc_stack)
249
self.pg = pg
250
251
instrs = [
252
InstrSpec('load_arg', pg('A[D]', 'S'),
253
code='o0 = i0; Py_INCREF(o0);'),
254
InstrSpec('load_const', pg('C[D]', 'S'),
255
code='o0 = i0; Py_INCREF(o0);'),
256
InstrSpec('return', pg('S', ''),
257
code='return i0;',
258
handles_own_decref=True),
259
InstrSpec('py_call', pg('C[D]S@D', 'S'),
260
handles_own_decref=True,
261
code=ri(0, """
262
PyObject *py_args = PyTuple_New(n_i1);
263
if (py_args == NULL) goto error;
264
int i;
265
for (i = 0; i < n_i1; i++) {
266
PyObject *arg = i1[i];
267
PyTuple_SET_ITEM(py_args, i, arg);
268
i1[i] = NULL;
269
}
270
o0 = PyObject_CallObject(i0, py_args);
271
Py_DECREF(py_args);
272
"""))
273
]
274
275
binops = [
276
('add', 'PyNumber_Add'),
277
('sub', 'PyNumber_Subtract'),
278
('mul', 'PyNumber_Multiply'),
279
('div', 'PyNumber_TrueDivide'),
280
('floordiv', 'PyNumber_FloorDivide')
281
]
282
283
for (name, op) in binops:
284
instrs.append(instr_funcall_2args(name, pg('SS', 'S'), op))
285
instrs.append(InstrSpec('pow', pg('SS', 'S'),
286
code='o0 = PyNumber_Power(i0, i1, Py_None);'))
287
instrs.append(InstrSpec('ipow', pg('SC[D]', 'S'),
288
code='o0 = PyNumber_Power(i0, i1, Py_None);'))
289
for (name, op) in [('neg', 'PyNumber_Negative'),
290
('invert', 'PyNumber_Invert'),
291
('abs', 'PyNumber_Absolute')]:
292
instrs.append(instr_unary(name, pg('S', 'S'), '%s(i0)' % op))
293
self.instr_descs = instrs
294
self._set_opcodes()
295
# Always use ipow
296
self.ipow_range = True
297
# We don't yet support call_c for Python-object interpreters
298
# (the default implementation doesn't work, because of
299
# object vs. PyObject* confusion)
300
self.implement_call_c = False
301
302