PageRenderTime 2ms CodeModel.GetById 48ms app.highlight 4ms RepoModel.GetById 2ms app.codeStats 0ms

/nuitka/codegen/templates/CodeTemplatesGeneratorFunction.py

https://bitbucket.org/pombredanne/nuitka
Python | 288 lines | 267 code | 1 blank | 20 comment | 1 complexity | c48b123ee1c5003fdfba2acc632cae32 MD5 | raw file
  1#     Copyright 2013, Kay Hayen, mailto:kay.hayen@gmail.com
  2#
  3#     Part of "Nuitka", an optimizing Python compiler that is compatible and
  4#     integrates with CPython, but also works on its own.
  5#
  6#     Licensed under the Apache License, Version 2.0 (the "License");
  7#     you may not use this file except in compliance with the License.
  8#     You may obtain a copy of the License at
  9#
 10#        http://www.apache.org/licenses/LICENSE-2.0
 11#
 12#     Unless required by applicable law or agreed to in writing, software
 13#     distributed under the License is distributed on an "AS IS" BASIS,
 14#     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15#     See the License for the specific language governing permissions and
 16#     limitations under the License.
 17#
 18""" Generator function (with yield) related templates.
 19
 20"""
 21
 22genfunc_context_body_template = """
 23
 24// This structure is for attachment as self of the generator function %(function_identifier)s and
 25// contains the common closure. It is allocated at the time the genexpr object is created.
 26struct _context_common_%(function_identifier)s_t
 27{
 28    // Ref count to keep track of common context usage and release only when it's the last one
 29    int ref_count;
 30
 31    // The generator function can access a read-only closure of the creator.
 32%(function_common_context_decl)s
 33};
 34
 35struct _context_generator_%(function_identifier)s_t
 36{
 37    _context_common_%(function_identifier)s_t *common_context;
 38
 39    // The generator function instance can access its parameters from creation time.
 40%(function_instance_context_decl)s
 41};
 42
 43static void _context_common_%(function_identifier)s_destructor( void *context_voidptr )
 44{
 45    _context_common_%(function_identifier)s_t *_python_context = (struct _context_common_%(function_identifier)s_t *)context_voidptr;
 46
 47    assert( _python_context->ref_count > 0 );
 48    _python_context->ref_count -= 1;
 49%(context_free)s
 50
 51    if ( _python_context->ref_count == 0 )
 52    {
 53        delete _python_context;
 54    }
 55}
 56
 57static void _context_generator_%(function_identifier)s_destructor( void *context_voidptr )
 58{
 59    _context_generator_%(function_identifier)s_t *_python_context = (struct _context_generator_%(function_identifier)s_t *)context_voidptr;
 60
 61    _context_common_%(function_identifier)s_destructor( _python_context->common_context );
 62
 63    delete _python_context;
 64}
 65"""
 66
 67genfunc_context_local_only_template = """
 68struct _context_generator_%(function_identifier)s_t
 69{
 70    // The generator function instance can access its parameters from creation time.
 71%(function_instance_context_decl)s
 72};
 73
 74static void _context_generator_%(function_identifier)s_destructor( void *context_voidptr )
 75{
 76    _context_generator_%(function_identifier)s_t *_python_context = (struct _context_generator_%(function_identifier)s_t *)context_voidptr;
 77
 78    delete _python_context;
 79}
 80"""
 81
 82make_genfunc_with_context_template = """
 83static PyObject *_MAKE_FUNCTION_%(function_identifier)s( %(function_creation_args)s )
 84{
 85    struct _context_common_%(function_identifier)s_t *_python_context = new _context_common_%(function_identifier)s_t;
 86    _python_context->ref_count = 1;
 87
 88    // Copy the parameter default values and closure values over.
 89%(context_copy)s
 90
 91    return Nuitka_Function_New(
 92        %(fparse_function_identifier)s,
 93        %(mparse_function_identifier)s,
 94        %(function_name_obj)s,
 95#if PYTHON_VERSION >= 330
 96        %(function_qualname_obj)s,
 97#endif
 98        %(code_identifier)s,
 99        %(defaults)s,
100#if PYTHON_VERSION >= 300
101        %(kwdefaults)s,
102        %(annotations)s,
103#endif
104        %(module_identifier)s,
105        %(function_doc)s,
106        _python_context,
107        _context_common_%(function_identifier)s_destructor
108    );
109}
110"""
111
112make_genfunc_without_context_template = """
113static PyObject *_MAKE_FUNCTION_%(function_identifier)s( %(function_creation_args)s )
114{
115    return Nuitka_Function_New(
116        %(fparse_function_identifier)s,
117        %(mparse_function_identifier)s,
118        %(function_name_obj)s,
119#if PYTHON_VERSION >= 330
120        %(function_qualname_obj)s,
121#endif
122        %(code_identifier)s,
123        %(defaults)s,
124#if PYTHON_VERSION >= 300
125        %(kwdefaults)s,
126        %(annotations)s,
127#endif
128        %(module_identifier)s,
129        %(function_doc)s
130    );
131}
132"""
133
134genfunc_yielder_template = """
135static void %(function_identifier)s_context( Nuitka_GeneratorObject *generator )
136{
137    {
138        // Make context accessible if one is used.
139%(context_access)s
140
141        // Local variable inits
142%(function_var_inits)s
143
144        // Actual function code.
145%(function_body)s
146    }
147
148    // TODO: Won't return, we should tell the compiler about that.
149    generator->m_yielded = NULL;
150    swapFiber( &generator->m_yielder_context, &generator->m_caller_context );
151}
152"""
153
154frame_guard_genfunc_template = """\
155static PyFrameObject *frame_%(frame_identifier)s = NULL;
156
157// Must be inside block, or else its d-tor will not be run.
158if ( isFrameUnusable( frame_%(frame_identifier)s ) )
159{
160    if ( frame_%(frame_identifier)s )
161    {
162#if _DEBUG_REFRAME
163        puts( "reframe for %(frame_identifier)s" );
164#endif
165        Py_DECREF( frame_%(frame_identifier)s );
166    }
167
168    frame_%(frame_identifier)s = MAKE_FRAME( %(code_identifier)s, %(module_identifier)s );
169}
170
171Py_INCREF( frame_%(frame_identifier)s );
172generator->m_frame = frame_%(frame_identifier)s;
173
174Py_CLEAR( generator->m_frame->f_back );
175
176generator->m_frame->f_back = PyThreadState_GET()->frame;
177Py_INCREF( generator->m_frame->f_back );
178
179PyThreadState_GET()->frame = generator->m_frame;
180
181FrameGuardLight frame_guard( &generator->m_frame );
182
183// TODO: The inject of the exception through C++ is very non-optimal, this flag
184// now indicates only if the exception occurs initially as supposed, or during
185// life, this could and should be shortcut.
186bool traceback;
187
188try
189{
190    // TODO: In case we don't raise exceptions ourselves, we would still have to do this, so
191    // beware to not optimize this away for generators without a replacement.
192    traceback = true;
193    CHECK_EXCEPTION( generator );
194    traceback = false;
195
196%(codes)s
197
198    PyErr_SetNone( PyExc_StopIteration );
199}
200catch ( PythonException &_exception )
201{
202    if ( !_exception.hasTraceback() )
203    {
204        _exception.setTraceback( %(tb_making)s );
205    }
206    else if ( traceback == false )
207    {
208        _exception.addTraceback( generator->m_frame );
209    }
210    _exception.toPython();
211
212    // TODO: Moving this code is not allowed yet.
213    generator->m_yielded = NULL;
214}"""
215
216genfunc_common_context_use_template = """\
217struct _context_common_%(function_identifier)s_t *_python_common_context = (struct _context_common_%(function_identifier)s_t *)self->m_context;
218struct _context_generator_%(function_identifier)s_t *_python_context = new _context_generator_%(function_identifier)s_t;
219
220_python_context->common_context = _python_common_context;
221_python_common_context->ref_count += 1;"""
222
223genfunc_local_context_use_template = """\
224struct _context_generator_%(function_identifier)s_t *_python_context = \
225new _context_generator_%(function_identifier)s_t;"""
226
227
228genfunc_generator_without_context_making = """\
229        PyObject *result = Nuitka_Generator_New(
230            %(function_identifier)s_context,
231            %(function_name_obj)s,
232            %(code_identifier)s
233        );"""
234
235genfunc_generator_with_context_making = """\
236        PyObject *result = Nuitka_Generator_New(
237            %(function_identifier)s_context,
238            %(function_name_obj)s,
239            %(code_identifier)s,
240            _python_context,
241            _context_generator_%(function_identifier)s_destructor
242        );"""
243
244
245genfunc_function_maker_template = """
246static PyObject *impl_%(function_identifier)s( %(parameter_objects_decl)s )
247{
248    // Create context if any
249%(context_making)s
250
251    try
252    {
253%(generator_making)s
254
255        if (unlikely( result == NULL ))
256        {
257            PyErr_Format( PyExc_RuntimeError, "cannot create function %(function_name)s" );
258            return NULL;
259        }
260
261        // Copy to context parameter values and closured variables if any.
262%(context_copy)s
263
264        return result;
265    }
266    catch ( PythonException &_exception )
267    {
268        _exception.toPython();
269
270        return NULL;
271    }
272}
273"""
274
275generator_context_access_template = """
276// The context of the generator.
277struct _context_common_%(function_identifier)s_t *_python_context = (struct _context_common_%(function_identifier)s_t *)self->m_context;
278"""
279
280generator_context_unused_template = """\
281// No context is used.
282"""
283
284# TODO: The NUITKA_MAY_BE_UNUSED is because Nuitka doesn't yet detect the case of unused
285# parameters (which are stored in the context for generators to share) reliably.
286generator_context_access_template2 = """
287NUITKA_MAY_BE_UNUSED struct _context_generator_%(function_identifier)s_t *_python_context = (_context_generator_%(function_identifier)s_t *)generator->m_context;
288"""