1 # cython: language_level = 2
7 cython
.declare(os
=object, re
=object, operator
=object,
8 Naming
=object, Options
=object, StringEncoding
=object,
9 Utils
=object, SourceDescriptor
=object, StringIOTree
=object,
10 DebugFlags
=object, basestring
=object)
15 from string
import Template
27 from Cython
import Utils
28 from Scanning
import SourceDescriptor
29 from Cython
.StringIOTree
import StringIOTree
33 from __builtin__
import basestring
35 from builtins
import str as basestring
37 KEYWORDS_MUST_BE_BYTES
= sys
.version_info
< (2,7)
40 non_portable_builtins_map
= {
41 # builtins that have different names in different Python versions
42 'bytes' : ('PY_MAJOR_VERSION < 3', 'str'),
43 'unicode' : ('PY_MAJOR_VERSION >= 3', 'str'),
44 'basestring' : ('PY_MAJOR_VERSION >= 3', 'str'),
45 'xrange' : ('PY_MAJOR_VERSION >= 3', 'range'),
46 'raw_input' : ('PY_MAJOR_VERSION >= 3', 'input'),
47 'BaseException' : ('PY_VERSION_HEX < 0x02050000', 'Exception'),
50 basicsize_builtins_map
= {
51 # builtins whose type has a different tp_basicsize than sizeof(...)
52 'PyTypeObject' : 'PyHeapTypeObject',
55 uncachable_builtins
= [
56 # builtin names that cannot be cached because they may or may not
57 # be available at import time
61 modifier_output_mapper
= {
62 'inline': 'CYTHON_INLINE'
65 is_self_assignment
= re
.compile(r
" *(\w+) = (\1);\s*$").match
68 def get_utility_dir():
69 # make this a function and not global variables:
70 # http://trac.cython.org/cython_trac/ticket/475
71 Cython_dir
= os
.path
.dirname(os
.path
.dirname(os
.path
.abspath(__file__
)))
72 return os
.path
.join(Cython_dir
, "Utility")
75 class UtilityCodeBase(object):
77 Support for loading utility code from a file.
79 Code sections in the file can be specified as follows:
81 ##### MyUtility.proto #####
85 ##### MyUtility.init #####
87 [code run at module initialization]
90 #@requires: MyOtherUtility
95 for prototypes and implementation respectively. For non-python or
96 -cython files backslashes should be used instead. 5 to 30 comment
97 characters may be used on either side.
99 If the @cname decorator is not used and this is a CythonUtilityCode,
100 one should pass in the 'name' keyword argument to be used for name
101 mangling of such entries.
104 is_cython_utility
= False
109 def _add_utility(cls
, utility
, type, lines
, begin_lineno
, tags
=None):
113 code
= '\n'.join(lines
)
114 if tags
and 'substitute' in tags
and tags
['substitute'] == set(['naming']):
115 del tags
['substitute']
117 code
= Template(code
).substitute(vars(Naming
))
118 except (KeyError, ValueError), e
:
119 raise RuntimeError("Error parsing templated utility code of type '%s' at line %d: %s" % (
120 type, begin_lineno
, e
))
122 # remember correct line numbers at least until after templating
123 code
= '\n' * begin_lineno
+ code
130 all_tags
= utility
[2]
131 if KEYWORDS_MUST_BE_BYTES
:
132 type = type.encode('ASCII')
133 all_tags
[type] = code
136 all_tags
= utility
[2]
137 for name
, values
in tags
.items():
138 if KEYWORDS_MUST_BE_BYTES
:
139 name
= name
.encode('ASCII')
140 all_tags
.setdefault(name
, set()).update(values
)
143 def load_utilities_from_file(cls
, path
):
144 utilities
= cls
._utility
_cache
.get(path
)
148 filename
= os
.path
.join(get_utility_dir(), path
)
149 _
, ext
= os
.path
.splitext(path
)
150 if ext
in ('.pyx', '.py', '.pxd', '.pxi'):
152 replace_comments
= re
.compile(r
'^\s*#.*').sub
155 replace_comments
= re
.compile(r
'^\s*//.*|^\s*/\*[^*]*\*/').sub
156 match_special
= re
.compile(
157 (r
'^%(C)s{5,30}\s*(?P<name>(?:\w|\.)+)\s*%(C)s{5,30}|'
158 r
'^%(C)s+@(?P<tag>\w+)\s*:\s*(?P<value>(?:\w|[.:])+)'
159 ) % {'C':comment
}).match
160 match_type
= re
.compile('(.+)[.](proto|impl|init|cleanup)$').match
162 f
= Utils
.open_source_file(filename
, encoding
='UTF-8')
164 all_lines
= f
.readlines()
171 utility
= type = None
174 for lineno
, line
in enumerate(all_lines
):
175 m
= match_special(line
)
178 cls
._add
_utility
(utility
, type, lines
, begin_lineno
, tags
)
180 begin_lineno
= lineno
+ 1
184 name
= m
.group('name')
185 mtype
= match_type(name
)
187 name
, type = mtype
.groups()
190 utility
= utilities
.setdefault(name
, [None, None, {}])
192 tags
.setdefault(m
.group('tag'), set()).add(m
.group('value'))
193 lines
.append('') # keep line number correct
195 lines
.append(replace_comments('', line
).rstrip())
198 raise ValueError("Empty utility code file")
200 # Don't forget to add the last utility code
201 cls
._add
_utility
(utility
, type, lines
, begin_lineno
, tags
)
203 cls
._utility
_cache
[path
] = utilities
207 def load(cls
, util_code_name
, from_file
=None, **kwargs
):
209 Load utility code from a file specified by from_file (relative to
210 Cython/Utility) and name util_code_name. If from_file is not given,
211 load it from the file util_code_name.*. There should be only one
212 file matched by this pattern.
214 if '::' in util_code_name
:
215 from_file
, util_code_name
= util_code_name
.rsplit('::', 1)
217 utility_dir
= get_utility_dir()
218 prefix
= util_code_name
+ '.'
220 listing
= os
.listdir(utility_dir
)
222 # XXX the code below assumes as 'zipimport.zipimporter' instance
223 # XXX should be easy to generalize, but too lazy right now to write it
227 archive
= loader
.archive
228 fileobj
= zipfile
.ZipFile(archive
)
229 listing
= [ os
.path
.basename(name
)
230 for name
in fileobj
.namelist()
231 if os
.path
.join(archive
, name
).startswith(utility_dir
)]
233 files
= [ os
.path
.join(utility_dir
, filename
)
234 for filename
in listing
235 if filename
.startswith(prefix
) ]
237 raise ValueError("No match found for utility code " + util_code_name
)
239 raise ValueError("More than one filename match found for utility code " + util_code_name
)
242 utilities
= cls
.load_utilities_from_file(from_file
)
243 proto
, impl
, tags
= utilities
[util_code_name
]
246 orig_kwargs
= kwargs
.copy()
247 for name
, values
in tags
.items():
250 # only pass lists when we have to: most argument expect one value or None
251 if name
== 'requires':
253 values
= [cls
.load(dep
, from_file
, **orig_kwargs
)
254 for dep
in sorted(values
)]
256 # dependencies are rarely unique, so use load_cached() when we can
257 values
= [cls
.load_cached(dep
, from_file
)
258 for dep
in sorted(values
)]
261 elif len(values
) == 1:
263 kwargs
[name
] = values
265 if proto
is not None:
266 kwargs
['proto'] = proto
268 kwargs
['impl'] = impl
270 if 'name' not in kwargs
:
271 kwargs
['name'] = util_code_name
273 if 'file' not in kwargs
and from_file
:
274 kwargs
['file'] = from_file
278 def load_cached(cls
, utility_code_name
, from_file
=None, __cache
={}):
280 Calls .load(), but using a per-type cache based on utility name and file name.
282 key
= (cls
, from_file
, utility_code_name
)
287 code
= __cache
[key
] = cls
.load(utility_code_name
, from_file
)
291 def load_as_string(cls
, util_code_name
, from_file
=None, **kwargs
):
293 Load a utility code as a string. Returns (proto, implementation)
295 util
= cls
.load(util_code_name
, from_file
, **kwargs
)
296 proto
, impl
= util
.proto
, util
.impl
297 return util
.format_code(proto
), util
.format_code(impl
)
299 def format_code(self
, code_string
, replace_empty_lines
=re
.compile(r
'\n\n+').sub
):
301 Format a code section for output.
304 code_string
= replace_empty_lines('\n', code_string
.strip()) + '\n\n'
308 return "<%s(%s)" % (type(self
).__name
__, self
.name
)
314 class UtilityCode(UtilityCodeBase
):
316 Stores utility code to add during code generation.
318 See GlobalState.put_utility_code.
320 hashes/equals by instance
323 impl implemenation code
324 init code to call on module initialization
325 requires utility code dependencies
326 proto_block the place in the resulting file where the prototype should
328 name name of the utility code (or None)
329 file filename of the utility code file this utility was loaded
333 def __init__(self
, proto
=None, impl
=None, init
=None, cleanup
=None, requires
=None,
334 proto_block
='utility_code_proto', name
=None, file=None):
335 # proto_block: Which code block to dump prototype in. See GlobalState.
339 self
.cleanup
= cleanup
340 self
.requires
= requires
342 self
.specialize_list
= []
343 self
.proto_block
= proto_block
348 return hash((self
.proto
, self
.impl
))
350 def __eq__(self
, other
):
353 if not isinstance(other
, type(self
)):
356 self_proto
= getattr(self
, 'proto', None)
357 other_proto
= getattr(other
, 'proto', None)
358 return (self_proto
, self
.impl
) == (other_proto
, other
.impl
)
360 def none_or_sub(self
, s
, context
):
362 Format a string in this utility code with context. If None, do nothing.
368 def specialize(self
, pyrex_type
=None, **data
):
369 # Dicts aren't hashable...
370 if pyrex_type
is not None:
371 data
['type'] = pyrex_type
.declaration_code('')
372 data
['type_name'] = pyrex_type
.specialization_name()
373 key
= tuple(sorted(data
.items()))
375 return self
._cache
[key
]
377 if self
.requires
is None:
380 requires
= [r
.specialize(data
) for r
in self
.requires
]
382 s
= self
._cache
[key
] = UtilityCode(
383 self
.none_or_sub(self
.proto
, data
),
384 self
.none_or_sub(self
.impl
, data
),
385 self
.none_or_sub(self
.init
, data
),
386 self
.none_or_sub(self
.cleanup
, data
),
390 self
.specialize_list
.append(s
)
393 def inject_string_constants(self
, impl
, output
):
394 """Replace 'PYIDENT("xyz")' by a constant Python identifier cname.
397 def externalise(matchobj
):
398 name
= matchobj
.group(1)
400 cname
= replacements
[name
]
402 cname
= replacements
[name
] = output
.get_interned_identifier(
403 StringEncoding
.EncodedString(name
)).cname
406 impl
= re
.sub('PYIDENT\("([^"]+)"\)', externalise
, impl
)
407 return bool(replacements
), impl
409 def put_code(self
, output
):
411 for dependency
in self
.requires
:
412 output
.use_utility_code(dependency
)
414 output
[self
.proto_block
].put_or_include(
415 self
.format_code(self
.proto
),
416 '%s_proto' % self
.name
)
418 impl
= self
.format_code(self
.impl
)
419 is_specialised
, impl
= self
.inject_string_constants(impl
, output
)
420 if not is_specialised
:
421 # no module specific adaptations => can be reused
422 output
['utility_code_def'].put_or_include(
423 impl
, '%s_impl' % self
.name
)
425 output
['utility_code_def'].put(impl
)
427 writer
= output
['init_globals']
428 writer
.putln("/* %s.init */" % self
.name
)
429 if isinstance(self
.init
, basestring
):
430 writer
.put(self
.format_code(self
.init
))
432 self
.init(writer
, output
.module_pos
)
433 writer
.putln(writer
.error_goto_if_PyErr(output
.module_pos
))
435 if self
.cleanup
and Options
.generate_cleanup_code
:
436 writer
= output
['cleanup_globals']
437 if isinstance(self
.cleanup
, basestring
):
438 writer
.put_or_include(
439 self
.format_code(self
.cleanup
),
440 '%s_cleanup' % self
.name
)
442 self
.cleanup(writer
, output
.module_pos
)
445 def sub_tempita(s
, context
, file=None, name
=None):
446 "Run tempita on string s with given context."
451 context
['__name'] = "%s:%s" % (file, name
)
453 context
['__name'] = name
455 from Cython
.Tempita
import sub
456 return sub(s
, **context
)
458 class TempitaUtilityCode(UtilityCode
):
459 def __init__(self
, name
=None, proto
=None, impl
=None, init
=None, file=None, context
=None, **kwargs
):
462 proto
= sub_tempita(proto
, context
, file, name
)
463 impl
= sub_tempita(impl
, context
, file, name
)
464 init
= sub_tempita(init
, context
, file, name
)
465 super(TempitaUtilityCode
, self
).__init
__(
466 proto
, impl
, init
=init
, name
=name
, file=file, **kwargs
)
468 def none_or_sub(self
, s
, context
):
470 Format a string in this utility code with context. If None, do nothing.
474 return sub_tempita(s
, context
, self
.file, self
.name
)
477 class LazyUtilityCode(UtilityCodeBase
):
479 Utility code that calls a callback with the root code writer when
480 available. Useful when you only have 'env' but not 'code'.
483 def __init__(self
, callback
):
484 self
.callback
= callback
486 def put_code(self
, globalstate
):
487 utility
= self
.callback(globalstate
.rootwriter
)
488 globalstate
.use_utility_code(utility
)
491 class FunctionState(object):
492 # return_label string function return point label
493 # error_label string error catch point label
494 # continue_label string loop continue point label
495 # break_label string loop break point label
496 # return_from_error_cleanup_label string
497 # label_counter integer counter for naming labels
498 # in_try_finally boolean inside try of try...finally
499 # exc_vars (string * 3) exception variables for reraise, or None
500 # can_trace boolean line tracing is supported in the current context
502 # Not used for now, perhaps later
503 def __init__(self
, owner
, names_taken
=set()):
504 self
.names_taken
= names_taken
507 self
.error_label
= None
508 self
.label_counter
= 0
509 self
.labels_used
= set()
510 self
.return_label
= self
.new_label()
511 self
.new_error_label()
512 self
.continue_label
= None
513 self
.break_label
= None
514 self
.yield_labels
= []
516 self
.in_try_finally
= 0
518 self
.can_trace
= False
520 self
.temps_allocated
= [] # of (name, type, manage_ref, static)
521 self
.temps_free
= {} # (type, manage_ref) -> list of free vars with same type/managed status
522 self
.temps_used_type
= {} # name -> (type, manage_ref)
523 self
.temp_counter
= 0
524 self
.closure_temps
= None
526 # This is used to collect temporaries, useful to find out which temps
527 # need to be privatized in parallel sections
528 self
.collect_temps_stack
= []
530 # This is used for the error indicator, which needs to be local to the
531 # function. It used to be global, which relies on the GIL being held.
532 # However, exceptions may need to be propagated through 'nogil'
533 # sections, in which case we introduce a race condition.
534 self
.should_declare_error_indicator
= False
535 self
.uses_error_indicator
= False
539 def new_label(self
, name
=None):
540 n
= self
.label_counter
541 self
.label_counter
= n
+ 1
542 label
= "%s%d" % (Naming
.label_prefix
, n
)
547 def new_yield_label(self
):
548 label
= self
.new_label('resume_from_yield')
549 num_and_label
= (len(self
.yield_labels
) + 1, label
)
550 self
.yield_labels
.append(num_and_label
)
553 def new_error_label(self
):
554 old_err_lbl
= self
.error_label
555 self
.error_label
= self
.new_label('error')
558 def get_loop_labels(self
):
563 def set_loop_labels(self
, labels
):
564 (self
.continue_label
,
565 self
.break_label
) = labels
567 def new_loop_labels(self
):
568 old_labels
= self
.get_loop_labels()
569 self
.set_loop_labels(
570 (self
.new_label("continue"),
571 self
.new_label("break")))
574 def get_all_labels(self
):
581 def set_all_labels(self
, labels
):
582 (self
.continue_label
,
585 self
.error_label
) = labels
587 def all_new_labels(self
):
588 old_labels
= self
.get_all_labels()
590 for old_label
, name
in zip(old_labels
, ['continue', 'break', 'return', 'error']):
592 new_labels
.append(self
.new_label(name
))
594 new_labels
.append(old_label
)
595 self
.set_all_labels(new_labels
)
598 def use_label(self
, lbl
):
599 self
.labels_used
.add(lbl
)
601 def label_used(self
, lbl
):
602 return lbl
in self
.labels_used
606 def allocate_temp(self
, type, manage_ref
, static
=False):
608 Allocates a temporary (which may create a new one or get a previously
609 allocated and released one of the same type). Type is simply registered
610 and handed back, but will usually be a PyrexType.
612 If type.is_pyobject, manage_ref comes into play. If manage_ref is set to
613 True, the temp will be decref-ed on return statements and in exception
614 handling clauses. Otherwise the caller has to deal with any reference
615 counting of the variable.
617 If not type.is_pyobject, then manage_ref will be ignored, but it
618 still has to be passed. It is recommended to pass False by convention
619 if it is known that type will never be a Python object.
621 static=True marks the temporary declaration with "static".
622 This is only used when allocating backing store for a module-level
625 A C string referring to the variable is returned.
628 type = type.const_base_type
629 if not type.is_pyobject
and not type.is_memoryviewslice
:
630 # Make manage_ref canonical, so that manage_ref will always mean
631 # a decref is needed.
634 freelist
= self
.temps_free
.get((type, manage_ref
))
635 if freelist
is not None and len(freelist
) > 0:
636 result
= freelist
.pop()
639 self
.temp_counter
+= 1
640 result
= "%s%d" % (Naming
.codewriter_temp_prefix
, self
.temp_counter
)
641 if not result
in self
.names_taken
: break
642 self
.temps_allocated
.append((result
, type, manage_ref
, static
))
643 self
.temps_used_type
[result
] = (type, manage_ref
)
644 if DebugFlags
.debug_temp_code_comments
:
645 self
.owner
.putln("/* %s allocated */" % result
)
647 if self
.collect_temps_stack
:
648 self
.collect_temps_stack
[-1].add((result
, type))
652 def release_temp(self
, name
):
654 Releases a temporary so that it can be reused by other code needing
655 a temp of the same type.
657 type, manage_ref
= self
.temps_used_type
[name
]
658 freelist
= self
.temps_free
.get((type, manage_ref
))
661 self
.temps_free
[(type, manage_ref
)] = freelist
663 raise RuntimeError("Temp %s freed twice!" % name
)
664 freelist
.append(name
)
665 if DebugFlags
.debug_temp_code_comments
:
666 self
.owner
.putln("/* %s released */" % name
)
668 def temps_in_use(self
):
669 """Return a list of (cname,type,manage_ref) tuples of temp names and their type
670 that are currently in use.
673 for name
, type, manage_ref
, static
in self
.temps_allocated
:
674 freelist
= self
.temps_free
.get((type, manage_ref
))
675 if freelist
is None or name
not in freelist
:
676 used
.append((name
, type, manage_ref
and type.is_pyobject
))
679 def temps_holding_reference(self
):
680 """Return a list of (cname,type) tuples of temp names and their type
681 that are currently in use. This includes only temps of a
682 Python object type which owns its reference.
685 for name
, type, manage_ref
in self
.temps_in_use()
686 if manage_ref
and type.is_pyobject
]
688 def all_managed_temps(self
):
689 """Return a list of (cname, type) tuples of refcount-managed Python objects.
691 return [(cname
, type)
692 for cname
, type, manage_ref
, static
in self
.temps_allocated
695 def all_free_managed_temps(self
):
696 """Return a list of (cname, type) tuples of refcount-managed Python
697 objects that are not currently in use. This is used by
698 try-except and try-finally blocks to clean up temps in the
701 return [(cname
, type)
702 for (type, manage_ref
), freelist
in self
.temps_free
.items()
704 for cname
in freelist
]
706 def start_collecting_temps(self
):
708 Useful to find out which temps were used in a code block
710 self
.collect_temps_stack
.append(set())
712 def stop_collecting_temps(self
):
713 return self
.collect_temps_stack
.pop()
715 def init_closure_temps(self
, scope
):
716 self
.closure_temps
= ClosureTempAllocator(scope
)
719 class NumConst(object):
720 """Global info about a Python number constant held by GlobalState.
724 py_type string int, long, float
725 value_code string evaluation code if different from value
728 def __init__(self
, cname
, value
, py_type
, value_code
=None):
731 self
.py_type
= py_type
732 self
.value_code
= value_code
or value
735 class PyObjectConst(object):
736 """Global info about a generic constant held by GlobalState.
741 def __init__(self
, cname
, type):
746 cython
.declare(possible_unicode_identifier
=object, possible_bytes_identifier
=object,
747 replace_identifier
=object, find_alphanums
=object)
748 possible_unicode_identifier
= re
.compile(ur
"(?![0-9])\w+$", re
.U
).match
749 possible_bytes_identifier
= re
.compile(r
"(?![0-9])\w+$".encode('ASCII')).match
750 replace_identifier
= re
.compile(r
'[^a-zA-Z0-9_]+').sub
751 find_alphanums
= re
.compile('([a-zA-Z0-9]+)').findall
753 class StringConst(object):
754 """Global info about a C string constant held by GlobalState.
757 # text EncodedString or BytesLiteral
758 # py_strings {(identifier, encoding) : PyStringConst}
760 def __init__(self
, cname
, text
, byte_string
):
763 self
.escaped_value
= StringEncoding
.escape_byte_string(byte_string
)
764 self
.py_strings
= None
765 self
.py_versions
= []
767 def add_py_version(self
, version
):
769 self
.py_versions
= [2,3]
770 elif version
not in self
.py_versions
:
771 self
.py_versions
.append(version
)
773 def get_py_string_const(self
, encoding
, identifier
=None,
774 is_str
=False, py3str_cstring
=None):
775 py_strings
= self
.py_strings
778 is_str
= bool(identifier
or is_str
)
779 is_unicode
= encoding
is None and not is_str
786 encoding
= encoding
.lower()
787 if encoding
in ('utf8', 'utf-8', 'ascii', 'usascii', 'us-ascii'):
791 encoding_key
= ''.join(find_alphanums(encoding
))
793 key
= (is_str
, is_unicode
, encoding_key
, py3str_cstring
)
794 if py_strings
is not None:
796 return py_strings
[key
]
804 elif identifier
is None:
805 if isinstance(text
, unicode):
806 intern = bool(possible_unicode_identifier(text
))
808 intern = bool(possible_bytes_identifier(text
))
812 prefix
= Naming
.interned_prefixes
['str']
814 prefix
= Naming
.py_const_prefix
817 encoding_prefix
= '_%s' % encoding_key
821 pystring_cname
= "%s%s%s_%s" % (
823 (is_str
and 's') or (is_unicode
and 'u') or 'b',
825 self
.cname
[len(Naming
.const_prefix
):])
827 py_string
= PyStringConst(
828 pystring_cname
, encoding
, is_unicode
, is_str
, py3str_cstring
, intern)
829 self
.py_strings
[key
] = py_string
832 class PyStringConst(object):
833 """Global info about a Python string constant held by GlobalState.
836 # py3str_cstring string
842 def __init__(self
, cname
, encoding
, is_unicode
, is_str
=False,
843 py3str_cstring
=None, intern=False):
845 self
.py3str_cstring
= py3str_cstring
846 self
.encoding
= encoding
848 self
.is_unicode
= is_unicode
851 def __lt__(self
, other
):
852 return self
.cname
< other
.cname
855 class GlobalState(object):
856 # filename_table {string : int} for finding filename table indexes
857 # filename_list [string] filenames in filename table order
858 # input_file_contents dict contents (=list of lines) of any file that was used as input
859 # to create this output C code. This is
860 # used to annotate the comments.
862 # utility_codes set IDs of used utility code (to avoid reinsertion)
864 # declared_cnames {string:Entry} used in a transition phase to merge pxd-declared
865 # constants etc. into the pyx-declared ones (i.e,
866 # check if constants are already added).
867 # In time, hopefully the literals etc. will be
868 # supplied directly instead.
870 # const_cnames_used dict global counter for unique constant identifiers
873 # parts {string:CCodeWriter}
880 # directives set Temporary variable used to track
881 # the current set of directives in the code generation
889 'utility_code_proto_before_types',
890 'numeric_typedefs', # Let these detailed individual parts stay!,
891 'complex_type_declarations', # as the proper solution is to make a full DAG...
892 'type_declarations', # More coarse-grained blocks would simply hide
893 'utility_code_proto', # the ugliness, not fix it
894 'module_declarations',
913 def __init__(self
, writer
, module_node
, emit_linenums
=False, common_utility_include_dir
=None):
914 self
.filename_table
= {}
915 self
.filename_list
= []
916 self
.input_file_contents
= {}
917 self
.utility_codes
= set()
918 self
.declared_cnames
= {}
919 self
.in_utility_code_generation
= False
920 self
.emit_linenums
= emit_linenums
921 self
.common_utility_include_dir
= common_utility_include_dir
923 self
.module_node
= module_node
# because some utility code generation needs it
924 # (generating backwards-compatible Get/ReleaseBuffer
926 self
.const_cnames_used
= {}
927 self
.string_const_index
= {}
928 self
.pyunicode_ptr_const_index
= {}
929 self
.num_const_index
= {}
930 self
.py_constants
= []
932 assert writer
.globalstate
is None
933 writer
.globalstate
= self
934 self
.rootwriter
= writer
936 def initialize_main_c_code(self
):
937 rootwriter
= self
.rootwriter
938 for part
in self
.code_layout
:
939 self
.parts
[part
] = rootwriter
.insertion_point()
941 if not Options
.cache_builtins
:
942 del self
.parts
['cached_builtins']
944 w
= self
.parts
['cached_builtins']
945 w
.enter_cfunc_scope()
946 w
.putln("static int __Pyx_InitCachedBuiltins(void) {")
948 w
= self
.parts
['cached_constants']
949 w
.enter_cfunc_scope()
951 w
.putln("static int __Pyx_InitCachedConstants(void) {")
952 w
.put_declare_refcount_context()
953 w
.put_setup_refcount_context("__Pyx_InitCachedConstants")
955 w
= self
.parts
['init_globals']
956 w
.enter_cfunc_scope()
958 w
.putln("static int __Pyx_InitGlobals(void) {")
960 if not Options
.generate_cleanup_code
:
961 del self
.parts
['cleanup_globals']
963 w
= self
.parts
['cleanup_globals']
964 w
.enter_cfunc_scope()
966 w
.putln("static void __Pyx_CleanupGlobals(void) {")
971 code
= self
.parts
['utility_code_def']
972 if self
.emit_linenums
:
973 code
.write('\n#line 1 "cython_utility"\n')
975 code
.putln("/* Runtime support code */")
977 def finalize_main_c_code(self
):
978 self
.close_global_decls()
983 code
= self
.parts
['utility_code_def']
984 code
.put(UtilityCode
.load_as_string("TypeConversions", "TypeConversion.c")[1])
987 def __getitem__(self
, key
):
988 return self
.parts
[key
]
991 # Global constants, interned objects, etc.
993 def close_global_decls(self
):
994 # This is called when it is known that no more global declarations will
996 self
.generate_const_declarations()
997 if Options
.cache_builtins
:
998 w
= self
.parts
['cached_builtins']
1000 if w
.label_used(w
.error_label
):
1001 w
.put_label(w
.error_label
)
1002 w
.putln("return -1;")
1004 w
.exit_cfunc_scope()
1006 w
= self
.parts
['cached_constants']
1007 w
.put_finish_refcount_context()
1008 w
.putln("return 0;")
1009 if w
.label_used(w
.error_label
):
1010 w
.put_label(w
.error_label
)
1011 w
.put_finish_refcount_context()
1012 w
.putln("return -1;")
1014 w
.exit_cfunc_scope()
1016 w
= self
.parts
['init_globals']
1017 w
.putln("return 0;")
1018 if w
.label_used(w
.error_label
):
1019 w
.put_label(w
.error_label
)
1020 w
.putln("return -1;")
1022 w
.exit_cfunc_scope()
1024 if Options
.generate_cleanup_code
:
1025 w
= self
.parts
['cleanup_globals']
1027 w
.exit_cfunc_scope()
1029 if Options
.generate_cleanup_code
:
1030 w
= self
.parts
['cleanup_module']
1032 w
.exit_cfunc_scope()
1034 def put_pyobject_decl(self
, entry
):
1035 self
['global_var'].putln("static PyObject *%s;" % entry
.cname
)
1037 # constant handling at code generation time
1039 def get_cached_constants_writer(self
):
1040 return self
.parts
['cached_constants']
1042 def get_int_const(self
, str_value
, longness
=False):
1043 py_type
= longness
and 'long' or 'int'
1045 c
= self
.num_const_index
[(str_value
, py_type
)]
1047 c
= self
.new_num_const(str_value
, py_type
)
1050 def get_float_const(self
, str_value
, value_code
):
1052 c
= self
.num_const_index
[(str_value
, 'float')]
1054 c
= self
.new_num_const(str_value
, 'float', value_code
)
1057 def get_py_const(self
, type, prefix
='', cleanup_level
=None):
1058 # create a new Python object constant
1059 const
= self
.new_py_const(type, prefix
)
1060 if cleanup_level
is not None \
1061 and cleanup_level
<= Options
.generate_cleanup_code
:
1062 cleanup_writer
= self
.parts
['cleanup_globals']
1063 cleanup_writer
.putln('Py_CLEAR(%s);' % const
.cname
)
1066 def get_string_const(self
, text
, py_version
=None):
1067 # return a C string constant, creating a new one if necessary
1069 byte_string
= text
.utf8encode()
1071 byte_string
= text
.byteencode()
1073 c
= self
.string_const_index
[byte_string
]
1075 c
= self
.new_string_const(text
, byte_string
)
1076 c
.add_py_version(py_version
)
1079 def get_pyunicode_ptr_const(self
, text
):
1080 # return a Py_UNICODE[] constant, creating a new one if necessary
1081 assert text
.is_unicode
1083 c
= self
.pyunicode_ptr_const_index
[text
]
1085 c
= self
.pyunicode_ptr_const_index
[text
] = self
.new_const_cname()
1088 def get_py_string_const(self
, text
, identifier
=None,
1089 is_str
=False, unicode_value
=None):
1090 # return a Python string constant, creating a new one if necessary
1091 py3str_cstring
= None
1092 if is_str
and unicode_value
is not None \
1093 and unicode_value
.utf8encode() != text
.byteencode():
1094 py3str_cstring
= self
.get_string_const(unicode_value
, py_version
=3)
1095 c_string
= self
.get_string_const(text
, py_version
=2)
1097 c_string
= self
.get_string_const(text
)
1098 py_string
= c_string
.get_py_string_const(
1099 text
.encoding
, identifier
, is_str
, py3str_cstring
)
1102 def get_interned_identifier(self
, text
):
1103 return self
.get_py_string_const(text
, identifier
=True)
1105 def new_string_const(self
, text
, byte_string
):
1106 cname
= self
.new_string_const_cname(byte_string
)
1107 c
= StringConst(cname
, text
, byte_string
)
1108 self
.string_const_index
[byte_string
] = c
1111 def new_num_const(self
, value
, py_type
, value_code
=None):
1112 cname
= self
.new_num_const_cname(value
, py_type
)
1113 c
= NumConst(cname
, value
, py_type
, value_code
)
1114 self
.num_const_index
[(value
, py_type
)] = c
1117 def new_py_const(self
, type, prefix
=''):
1118 cname
= self
.new_const_cname(prefix
)
1119 c
= PyObjectConst(cname
, type)
1120 self
.py_constants
.append(c
)
1123 def new_string_const_cname(self
, bytes_value
):
1124 # Create a new globally-unique nice name for a C string constant.
1125 value
= bytes_value
.decode('ASCII', 'ignore')
1126 return self
.new_const_cname(value
=value
)
1128 def new_num_const_cname(self
, value
, py_type
):
1129 if py_type
== 'long':
1132 prefix
= Naming
.interned_prefixes
[py_type
]
1133 cname
= "%s%s" % (prefix
, value
)
1134 cname
= cname
.replace('+', '_').replace('-', 'neg_').replace('.', '_')
1137 def new_const_cname(self
, prefix
='', value
=''):
1138 value
= replace_identifier('_', value
)[:32].strip('_')
1139 used
= self
.const_cnames_used
1141 while name_suffix
in used
:
1142 counter
= used
[value
] = used
[value
] + 1
1143 name_suffix
= '%s_%d' % (value
, counter
)
1144 used
[name_suffix
] = 1
1146 prefix
= Naming
.interned_prefixes
[prefix
]
1148 prefix
= Naming
.const_prefix
1149 return "%s%s" % (prefix
, name_suffix
)
1151 def add_cached_builtin_decl(self
, entry
):
1152 if entry
.is_builtin
and entry
.is_const
:
1153 if self
.should_declare(entry
.cname
, entry
):
1154 self
.put_pyobject_decl(entry
)
1155 w
= self
.parts
['cached_builtins']
1157 if entry
.name
in non_portable_builtins_map
:
1158 condition
, replacement
= non_portable_builtins_map
[entry
.name
]
1159 w
.putln('#if %s' % condition
)
1160 self
.put_cached_builtin_init(
1161 entry
.pos
, StringEncoding
.EncodedString(replacement
),
1164 self
.put_cached_builtin_init(
1165 entry
.pos
, StringEncoding
.EncodedString(entry
.name
),
1170 def put_cached_builtin_init(self
, pos
, name
, cname
):
1171 w
= self
.parts
['cached_builtins']
1172 interned_cname
= self
.get_interned_identifier(name
).cname
1173 self
.use_utility_code(
1174 UtilityCode
.load_cached("GetBuiltinName", "ObjectHandling.c"))
1175 w
.putln('%s = __Pyx_GetBuiltinName(%s); if (!%s) %s' % (
1181 def generate_const_declarations(self
):
1182 self
.generate_string_constants()
1183 self
.generate_num_constants()
1184 self
.generate_object_constant_decls()
1186 def generate_object_constant_decls(self
):
1187 consts
= [ (len(c
.cname
), c
.cname
, c
)
1188 for c
in self
.py_constants
]
1190 decls_writer
= self
.parts
['decls']
1191 for _
, cname
, c
in consts
:
1193 "static %s;" % c
.type.declaration_code(cname
))
1195 def generate_string_constants(self
):
1196 c_consts
= [ (len(c
.cname
), c
.cname
, c
)
1197 for c
in self
.string_const_index
.values() ]
1201 decls_writer
= self
.parts
['decls']
1202 for _
, cname
, c
in c_consts
:
1204 if c
.py_versions
and (2 not in c
.py_versions
or 3 not in c
.py_versions
):
1206 decls_writer
.putln("#if PY_MAJOR_VERSION %s 3" % (
1207 (2 in c
.py_versions
) and '<' or '>='))
1208 decls_writer
.putln('static char %s[] = "%s";' % (
1209 cname
, StringEncoding
.split_string_literal(c
.escaped_value
)))
1211 decls_writer
.putln("#endif")
1212 if c
.py_strings
is not None:
1213 for py_string
in c
.py_strings
.values():
1214 py_strings
.append((c
.cname
, len(py_string
.cname
), py_string
))
1216 for c
, cname
in self
.pyunicode_ptr_const_index
.items():
1217 utf16_array
, utf32_array
= StringEncoding
.encode_pyunicode_string(c
)
1219 # Narrow and wide representations differ
1220 decls_writer
.putln("#ifdef Py_UNICODE_WIDE")
1221 decls_writer
.putln("static Py_UNICODE %s[] = { %s };" % (cname
, utf32_array
))
1223 decls_writer
.putln("#else")
1224 decls_writer
.putln("static Py_UNICODE %s[] = { %s };" % (cname
, utf16_array
))
1225 decls_writer
.putln("#endif")
1228 self
.use_utility_code(UtilityCode
.load_cached("InitStrings", "StringTools.c"))
1230 w
= self
.parts
['pystring_table']
1232 w
.putln("static __Pyx_StringTabEntry %s[] = {" %
1233 Naming
.stringtab_cname
)
1234 for c_cname
, _
, py_string
in py_strings
:
1235 if not py_string
.is_str
or not py_string
.encoding
or \
1236 py_string
.encoding
in ('ASCII', 'USASCII', 'US-ASCII',
1240 encoding
= '"%s"' % py_string
.encoding
.lower()
1243 "static PyObject *%s;" % py_string
.cname
)
1244 if py_string
.py3str_cstring
:
1245 w
.putln("#if PY_MAJOR_VERSION >= 3")
1247 "{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % (
1249 py_string
.py3str_cstring
.cname
,
1250 py_string
.py3str_cstring
.cname
,
1256 "{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % (
1261 py_string
.is_unicode
,
1265 if py_string
.py3str_cstring
:
1267 w
.putln("{0, 0, 0, 0, 0, 0, 0}")
1270 init_globals
= self
.parts
['init_globals']
1272 "if (__Pyx_InitStrings(%s) < 0) %s;" % (
1273 Naming
.stringtab_cname
,
1274 init_globals
.error_goto(self
.module_pos
)))
1276 def generate_num_constants(self
):
1277 consts
= [(c
.py_type
, c
.value
[0] == '-', len(c
.value
), c
.value
, c
.value_code
, c
)
1278 for c
in self
.num_const_index
.values()]
1280 decls_writer
= self
.parts
['decls']
1281 init_globals
= self
.parts
['init_globals']
1282 for py_type
, _
, _
, value
, value_code
, c
in consts
:
1284 decls_writer
.putln("static PyObject *%s;" % cname
)
1285 if py_type
== 'float':
1286 function
= 'PyFloat_FromDouble(%s)'
1287 elif py_type
== 'long':
1288 function
= 'PyLong_FromString((char *)"%s", 0, 0)'
1289 elif Utils
.long_literal(value
):
1290 function
= 'PyInt_FromString((char *)"%s", 0, 0)'
1291 elif len(value
.lstrip('-')) > 4:
1292 function
= "PyInt_FromLong(%sL)"
1294 function
= "PyInt_FromLong(%s)"
1295 init_globals
.putln('%s = %s; %s' % (
1296 cname
, function
% value_code
,
1297 init_globals
.error_goto_if_null(cname
, self
.module_pos
)))
1299 # The functions below are there in a transition phase only
1300 # and will be deprecated. They are called from Nodes.BlockNode.
1301 # The copy&paste duplication is intentional in order to be able
1302 # to see quickly how BlockNode worked, until this is replaced.
1304 def should_declare(self
, cname
, entry
):
1305 if cname
in self
.declared_cnames
:
1306 other
= self
.declared_cnames
[cname
]
1307 assert str(entry
.type) == str(other
.type)
1308 assert entry
.init
== other
.init
1311 self
.declared_cnames
[cname
] = entry
1318 def lookup_filename(self
, filename
):
1320 index
= self
.filename_table
[filename
]
1322 index
= len(self
.filename_list
)
1323 self
.filename_list
.append(filename
)
1324 self
.filename_table
[filename
] = index
1327 def commented_file_contents(self
, source_desc
):
1329 return self
.input_file_contents
[source_desc
]
1332 source_file
= source_desc
.get_lines(encoding
='ASCII',
1333 error_handling
='ignore')
1335 F
= [u
' * ' + line
.rstrip().replace(
1336 u
'*/', u
'*[inserted by cython to avoid comment closer]/'
1338 u
'/*', u
'/[inserted by cython to avoid comment start]*'
1340 for line
in source_file
]
1342 if hasattr(source_file
, 'close'):
1344 if not F
: F
.append(u
'')
1345 self
.input_file_contents
[source_desc
] = F
1349 # Utility code state
1352 def use_utility_code(self
, utility_code
):
1354 Adds code to the C file. utility_code should
1355 a) implement __eq__/__hash__ for the purpose of knowing whether the same
1356 code has already been included
1357 b) implement put_code, which takes a globalstate instance
1361 if utility_code
not in self
.utility_codes
:
1362 self
.utility_codes
.add(utility_code
)
1363 utility_code
.put_code(self
)
1366 def funccontext_property(name
):
1367 attribute_of
= operator
.attrgetter(name
)
1369 return attribute_of(self
.funcstate
)
1370 def set(self
, value
):
1371 setattr(self
.funcstate
, name
, value
)
1372 return property(get
, set)
1375 class CCodeWriter(object):
1377 Utility class to output C code.
1379 When creating an insertion point one must care about the state that is
1381 - formatting state (level, bol) is cloned and used in insertion points
1383 - labels, temps, exc_vars: One must construct a scope in which these can
1384 exist by calling enter_cfunc_scope/exit_cfunc_scope (these are for
1385 sanity checking and forward compatabilty). Created insertion points
1386 looses this scope and cannot access it.
1387 - marker: Not copied to insertion point
1388 - filename_table, filename_list, input_file_contents: All codewriters
1389 coming from the same root share the same instances simultaneously.
1392 # f file output file
1393 # buffer StringIOTree
1395 # level int indentation level
1396 # bol bool beginning of line?
1397 # marker string comment to emit before next line
1398 # funcstate FunctionState contains state local to a C function used for code
1399 # generation (labels and temps state etc.)
1400 # globalstate GlobalState contains state global for a C file (input file info,
1401 # utility code, declared constants etc.)
1402 # emit_linenums boolean whether or not to write #line pragmas
1404 # c_line_in_traceback boolean append the c file and line number to the traceback for exceptions
1406 # pyclass_stack list used during recursive code generation to pass information
1407 # about the current class one is in
1411 def __init__(self
, create_from
=None, buffer=None, copy_formatting
=False, emit_linenums
=None, c_line_in_traceback
=True):
1412 if buffer is None: buffer = StringIOTree()
1413 self
.buffer = buffer
1415 self
.last_marker_line
= 0
1416 self
.source_desc
= ""
1417 self
.pyclass_stack
= []
1419 self
.funcstate
= None
1424 if create_from
is not None:
1425 # Use same global state
1426 self
.globalstate
= create_from
.globalstate
1427 self
.funcstate
= create_from
.funcstate
1428 # Clone formatting state
1430 self
.level
= create_from
.level
1431 self
.bol
= create_from
.bol
1432 self
.call_level
= create_from
.call_level
1434 if emit_linenums
is None and self
.globalstate
:
1435 self
.emit_linenums
= self
.globalstate
.emit_linenums
1437 self
.emit_linenums
= emit_linenums
1438 self
.c_line_in_traceback
= c_line_in_traceback
1440 def create_new(self
, create_from
, buffer, copy_formatting
):
1441 # polymorphic constructor -- very slightly more versatile
1442 # than using __class__
1443 result
= CCodeWriter(create_from
, buffer, copy_formatting
,
1444 c_line_in_traceback
=self
.c_line_in_traceback
)
1447 def copyto(self
, f
):
1448 self
.buffer.copyto(f
)
1451 return self
.buffer.getvalue()
1454 # also put invalid markers (lineno 0), to indicate that those lines
1455 # have no Cython source code correspondence
1456 if self
.marker
is None:
1457 cython_lineno
= self
.last_marker_line
1459 cython_lineno
= self
.marker
[0]
1461 self
.buffer.markers
.extend([cython_lineno
] * s
.count('\n'))
1462 self
.buffer.write(s
)
1464 def insertion_point(self
):
1465 other
= self
.create_new(create_from
=self
, buffer=self
.buffer.insertion_point(), copy_formatting
=True)
1468 def new_writer(self
):
1470 Creates a new CCodeWriter connected to the same global state, which
1471 can later be inserted using insert.
1473 return CCodeWriter(create_from
=self
, c_line_in_traceback
=self
.c_line_in_traceback
)
1475 def insert(self
, writer
):
1477 Inserts the contents of another code writer (created with
1478 the same global state) in the current location.
1480 It is ok to write to the inserted writer also after insertion.
1482 assert writer
.globalstate
is self
.globalstate
1483 self
.buffer.insert(writer
.buffer)
1485 # Properties delegated to function scope
1486 label_counter
= funccontext_property("label_counter")
1487 return_label
= funccontext_property("return_label")
1488 error_label
= funccontext_property("error_label")
1489 labels_used
= funccontext_property("labels_used")
1490 continue_label
= funccontext_property("continue_label")
1491 break_label
= funccontext_property("break_label")
1492 return_from_error_cleanup_label
= funccontext_property("return_from_error_cleanup_label")
1493 yield_labels
= funccontext_property("yield_labels")
1495 # Functions delegated to function scope
1496 def new_label(self
, name
=None): return self
.funcstate
.new_label(name
)
1497 def new_error_label(self
): return self
.funcstate
.new_error_label()
1498 def new_yield_label(self
): return self
.funcstate
.new_yield_label()
1499 def get_loop_labels(self
): return self
.funcstate
.get_loop_labels()
1500 def set_loop_labels(self
, labels
): return self
.funcstate
.set_loop_labels(labels
)
1501 def new_loop_labels(self
): return self
.funcstate
.new_loop_labels()
1502 def get_all_labels(self
): return self
.funcstate
.get_all_labels()
1503 def set_all_labels(self
, labels
): return self
.funcstate
.set_all_labels(labels
)
1504 def all_new_labels(self
): return self
.funcstate
.all_new_labels()
1505 def use_label(self
, lbl
): return self
.funcstate
.use_label(lbl
)
1506 def label_used(self
, lbl
): return self
.funcstate
.label_used(lbl
)
1509 def enter_cfunc_scope(self
):
1510 self
.funcstate
= FunctionState(self
)
1512 def exit_cfunc_scope(self
):
1513 self
.funcstate
= None
1517 def get_py_int(self
, str_value
, longness
):
1518 return self
.globalstate
.get_int_const(str_value
, longness
).cname
1520 def get_py_float(self
, str_value
, value_code
):
1521 return self
.globalstate
.get_float_const(str_value
, value_code
).cname
1523 def get_py_const(self
, type, prefix
='', cleanup_level
=None):
1524 return self
.globalstate
.get_py_const(type, prefix
, cleanup_level
).cname
1526 def get_string_const(self
, text
):
1527 return self
.globalstate
.get_string_const(text
).cname
1529 def get_pyunicode_ptr_const(self
, text
):
1530 return self
.globalstate
.get_pyunicode_ptr_const(text
)
1532 def get_py_string_const(self
, text
, identifier
=None,
1533 is_str
=False, unicode_value
=None):
1534 return self
.globalstate
.get_py_string_const(
1535 text
, identifier
, is_str
, unicode_value
).cname
1537 def get_argument_default_const(self
, type):
1538 return self
.globalstate
.get_py_const(type).cname
1540 def intern(self
, text
):
1541 return self
.get_py_string_const(text
)
1543 def intern_identifier(self
, text
):
1544 return self
.get_py_string_const(text
, identifier
=True)
1546 def get_cached_constants_writer(self
):
1547 return self
.globalstate
.get_cached_constants_writer()
1551 def putln(self
, code
="", safe
=False):
1552 if self
.marker
and self
.bol
:
1554 if self
.emit_linenums
and self
.last_marker_line
!= 0:
1555 self
.write('\n#line %s "%s"\n' % (self
.last_marker_line
, self
.source_desc
))
1565 def emit_marker(self
):
1568 self
.write("/* %s */\n" % self
.marker
[1])
1569 if (self
.funcstate
and self
.funcstate
.can_trace
1570 and self
.globalstate
.directives
['linetrace']):
1572 self
.write('__Pyx_TraceLine(%d)\n' % self
.marker
[0])
1573 self
.last_marker_line
= self
.marker
[0]
1576 def put_safe(self
, code
):
1577 # put code, but ignore {}
1581 def put_or_include(self
, code
, name
):
1582 include_dir
= self
.globalstate
.common_utility_include_dir
1583 if include_dir
and len(code
) > 1024:
1584 include_file
= "%s_%s.h" % (
1585 name
, hashlib
.md5(code
.encode('utf8')).hexdigest())
1586 path
= os
.path
.join(include_dir
, include_file
)
1587 if not os
.path
.exists(path
):
1588 tmp_path
= '%s.tmp%s' % (path
, os
.getpid())
1589 f
= Utils
.open_new_file(tmp_path
)
1594 os
.rename(tmp_path
, path
)
1595 code
= '#include "%s"\n' % path
1598 def put(self
, code
):
1599 if is_self_assignment(code
):
1603 dl
= code
.count("{")
1607 dl
-= code
.count("}")
1610 elif dl
== 0 and code
[0] == "}":
1611 # special cases like "} else {" need a temporary dedent
1623 def putln_tempita(self
, code
, **context
):
1624 from Cython
.Tempita
import sub
1625 self
.putln(sub(code
, **context
))
1627 def put_tempita(self
, code
, **context
):
1628 from Cython
.Tempita
import sub
1629 self
.put(sub(code
, **context
))
1631 def increase_indent(self
):
1634 def decrease_indent(self
):
1637 def begin_block(self
):
1639 self
.increase_indent()
1641 def end_block(self
):
1642 self
.decrease_indent()
1646 self
.write(" " * self
.level
)
1648 def get_py_version_hex(self
, pyversion
):
1649 return "0x%02X%02X%02X%02X" % (tuple(pyversion
) + (0,0,0,0))[:4]
1651 def mark_pos(self
, pos
):
1654 source_desc
, line
, col
= pos
1655 if self
.last_marker_line
== line
:
1657 assert isinstance(source_desc
, SourceDescriptor
)
1658 contents
= self
.globalstate
.commented_file_contents(source_desc
)
1659 lines
= contents
[max(0, line
-3):line
] # line numbers start at 1
1660 lines
[-1] += u
' # <<<<<<<<<<<<<<'
1661 lines
+= contents
[line
:line
+2]
1663 marker
= u
'"%s":%d\n%s\n' % (
1664 source_desc
.get_escaped_description(), line
, u
'\n'.join(lines
))
1665 self
.marker
= (line
, marker
)
1666 if self
.emit_linenums
:
1667 self
.source_desc
= source_desc
.get_escaped_description()
1669 def put_label(self
, lbl
):
1670 if lbl
in self
.funcstate
.labels_used
:
1671 self
.putln("%s:;" % lbl
)
1673 def put_goto(self
, lbl
):
1674 self
.funcstate
.use_label(lbl
)
1675 self
.putln("goto %s;" % lbl
)
1677 def put_var_declaration(self
, entry
, storage_class
="",
1678 dll_linkage
=None, definition
=True):
1679 #print "Code.put_var_declaration:", entry.name, "definition =", definition ###
1680 if entry
.visibility
== 'private' and not (definition
or entry
.defined_in_pxd
):
1681 #print "...private and not definition, skipping", entry.cname ###
1683 if entry
.visibility
== "private" and not entry
.used
:
1684 #print "...private and not used, skipping", entry.cname ###
1687 self
.put("%s " % storage_class
)
1688 if not entry
.cf_used
:
1689 self
.put('CYTHON_UNUSED ')
1690 self
.put(entry
.type.declaration_code(
1691 entry
.cname
, dll_linkage
=dll_linkage
))
1692 if entry
.init
is not None:
1693 self
.put_safe(" = %s" % entry
.type.literal_code(entry
.init
))
1694 elif entry
.type.is_pyobject
:
1698 def put_temp_declarations(self
, func_context
):
1699 for name
, type, manage_ref
, static
in func_context
.temps_allocated
:
1700 decl
= type.declaration_code(name
)
1701 if type.is_pyobject
:
1702 self
.putln("%s = NULL;" % decl
)
1703 elif type.is_memoryviewslice
:
1705 self
.putln("%s = %s;" % (decl
, MemoryView
.memslice_entry_init
))
1707 self
.putln("%s%s;" % (static
and "static " or "", decl
))
1709 if func_context
.should_declare_error_indicator
:
1710 if self
.funcstate
.uses_error_indicator
:
1713 unused
= 'CYTHON_UNUSED '
1714 # Initialize these variables to silence compiler warnings
1715 self
.putln("%sint %s = 0;" % (unused
, Naming
.lineno_cname
))
1716 self
.putln("%sconst char *%s = NULL;" % (unused
, Naming
.filename_cname
))
1717 self
.putln("%sint %s = 0;" % (unused
, Naming
.clineno_cname
))
1719 def put_h_guard(self
, guard
):
1720 self
.putln("#ifndef %s" % guard
)
1721 self
.putln("#define %s" % guard
)
1723 def unlikely(self
, cond
):
1724 if Options
.gcc_branch_hints
:
1725 return 'unlikely(%s)' % cond
1729 def build_function_modifiers(self
, modifiers
, mapper
=modifier_output_mapper
):
1732 return '%s ' % ' '.join([mapper(m
,m
) for m
in modifiers
])
1734 # Python objects and reference counting
1736 def entry_as_pyobject(self
, entry
):
1738 if (not entry
.is_self_arg
and not entry
.type.is_complete()
1739 or entry
.type.is_extension_type
):
1740 return "(PyObject *)" + entry
.cname
1744 def as_pyobject(self
, cname
, type):
1745 from PyrexTypes
import py_object_type
, typecast
1746 return typecast(py_object_type
, type, cname
)
1748 def put_gotref(self
, cname
):
1749 self
.putln("__Pyx_GOTREF(%s);" % cname
)
1751 def put_giveref(self
, cname
):
1752 self
.putln("__Pyx_GIVEREF(%s);" % cname
)
1754 def put_xgiveref(self
, cname
):
1755 self
.putln("__Pyx_XGIVEREF(%s);" % cname
)
1757 def put_xgotref(self
, cname
):
1758 self
.putln("__Pyx_XGOTREF(%s);" % cname
)
1760 def put_incref(self
, cname
, type, nanny
=True):
1762 self
.putln("__Pyx_INCREF(%s);" % self
.as_pyobject(cname
, type))
1764 self
.putln("Py_INCREF(%s);" % self
.as_pyobject(cname
, type))
1766 def put_decref(self
, cname
, type, nanny
=True):
1767 self
._put
_decref
(cname
, type, nanny
, null_check
=False, clear
=False)
1769 def put_var_gotref(self
, entry
):
1770 if entry
.type.is_pyobject
:
1771 self
.putln("__Pyx_GOTREF(%s);" % self
.entry_as_pyobject(entry
))
1773 def put_var_giveref(self
, entry
):
1774 if entry
.type.is_pyobject
:
1775 self
.putln("__Pyx_GIVEREF(%s);" % self
.entry_as_pyobject(entry
))
1777 def put_var_xgotref(self
, entry
):
1778 if entry
.type.is_pyobject
:
1779 self
.putln("__Pyx_XGOTREF(%s);" % self
.entry_as_pyobject(entry
))
1781 def put_var_xgiveref(self
, entry
):
1782 if entry
.type.is_pyobject
:
1783 self
.putln("__Pyx_XGIVEREF(%s);" % self
.entry_as_pyobject(entry
))
1785 def put_var_incref(self
, entry
):
1786 if entry
.type.is_pyobject
:
1787 self
.putln("__Pyx_INCREF(%s);" % self
.entry_as_pyobject(entry
))
1789 def put_decref_clear(self
, cname
, type, nanny
=True, clear_before_decref
=False):
1790 self
._put
_decref
(cname
, type, nanny
, null_check
=False,
1791 clear
=True, clear_before_decref
=clear_before_decref
)
1793 def put_xdecref(self
, cname
, type, nanny
=True, have_gil
=True):
1794 self
._put
_decref
(cname
, type, nanny
, null_check
=True,
1795 have_gil
=have_gil
, clear
=False)
1797 def put_xdecref_clear(self
, cname
, type, nanny
=True, clear_before_decref
=False):
1798 self
._put
_decref
(cname
, type, nanny
, null_check
=True,
1799 clear
=True, clear_before_decref
=clear_before_decref
)
1801 def _put_decref(self
, cname
, type, nanny
=True, null_check
=False,
1802 have_gil
=True, clear
=False, clear_before_decref
=False):
1803 if type.is_memoryviewslice
:
1804 self
.put_xdecref_memoryviewslice(cname
, have_gil
=have_gil
)
1807 prefix
= nanny
and '__Pyx' or 'Py'
1808 X
= null_check
and 'X' or ''
1811 if clear_before_decref
:
1813 X
= '' # CPython doesn't have a Py_XCLEAR()
1814 self
.putln("%s_%sCLEAR(%s);" % (prefix
, X
, cname
))
1816 self
.putln("%s_%sDECREF(%s); %s = 0;" % (
1817 prefix
, X
, self
.as_pyobject(cname
, type), cname
))
1819 self
.putln("%s_%sDECREF(%s);" % (
1820 prefix
, X
, self
.as_pyobject(cname
, type)))
1822 def put_decref_set(self
, cname
, rhs_cname
):
1823 self
.putln("__Pyx_DECREF_SET(%s, %s);" % (cname
, rhs_cname
))
1825 def put_xdecref_set(self
, cname
, rhs_cname
):
1826 self
.putln("__Pyx_XDECREF_SET(%s, %s);" % (cname
, rhs_cname
))
1828 def put_var_decref(self
, entry
):
1829 if entry
.type.is_pyobject
:
1830 self
.putln("__Pyx_XDECREF(%s);" % self
.entry_as_pyobject(entry
))
1832 def put_var_xdecref(self
, entry
):
1833 if entry
.type.is_pyobject
:
1834 self
.putln("__Pyx_XDECREF(%s);" % self
.entry_as_pyobject(entry
))
1836 def put_var_decref_clear(self
, entry
):
1837 self
._put
_var
_decref
_clear
(entry
, null_check
=False)
1839 def put_var_xdecref_clear(self
, entry
):
1840 self
._put
_var
_decref
_clear
(entry
, null_check
=True)
1842 def _put_var_decref_clear(self
, entry
, null_check
):
1843 if entry
.type.is_pyobject
:
1844 if entry
.in_closure
:
1845 # reset before DECREF to make sure closure state is
1846 # consistent during call to DECREF()
1847 self
.putln("__Pyx_%sCLEAR(%s);" % (
1848 null_check
and 'X' or '',
1851 self
.putln("__Pyx_%sDECREF(%s); %s = 0;" % (
1852 null_check
and 'X' or '',
1853 self
.entry_as_pyobject(entry
),
1856 def put_var_decrefs(self
, entries
, used_only
= 0):
1857 for entry
in entries
:
1858 if not used_only
or entry
.used
:
1859 if entry
.xdecref_cleanup
:
1860 self
.put_var_xdecref(entry
)
1862 self
.put_var_decref(entry
)
1864 def put_var_xdecrefs(self
, entries
):
1865 for entry
in entries
:
1866 self
.put_var_xdecref(entry
)
1868 def put_var_xdecrefs_clear(self
, entries
):
1869 for entry
in entries
:
1870 self
.put_var_xdecref_clear(entry
)
1872 def put_incref_memoryviewslice(self
, slice_cname
, have_gil
=False):
1874 self
.globalstate
.use_utility_code(MemoryView
.memviewslice_init_code
)
1875 self
.putln("__PYX_INC_MEMVIEW(&%s, %d);" % (slice_cname
, int(have_gil
)))
1877 def put_xdecref_memoryviewslice(self
, slice_cname
, have_gil
=False):
1879 self
.globalstate
.use_utility_code(MemoryView
.memviewslice_init_code
)
1880 self
.putln("__PYX_XDEC_MEMVIEW(&%s, %d);" % (slice_cname
, int(have_gil
)))
1882 def put_xgiveref_memoryviewslice(self
, slice_cname
):
1883 self
.put_xgiveref("%s.memview" % slice_cname
)
1885 def put_init_to_py_none(self
, cname
, type, nanny
=True):
1886 from PyrexTypes
import py_object_type
, typecast
1887 py_none
= typecast(type, py_object_type
, "Py_None")
1889 self
.putln("%s = %s; __Pyx_INCREF(Py_None);" % (cname
, py_none
))
1891 self
.putln("%s = %s; Py_INCREF(Py_None);" % (cname
, py_none
))
1893 def put_init_var_to_py_none(self
, entry
, template
= "%s", nanny
=True):
1894 code
= template
% entry
.cname
1895 #if entry.type.is_extension_type:
1896 # code = "((PyObject*)%s)" % code
1897 self
.put_init_to_py_none(code
, entry
.type, nanny
)
1898 if entry
.in_closure
:
1899 self
.put_giveref('Py_None')
1901 def put_pymethoddef(self
, entry
, term
, allow_skip
=True):
1902 if entry
.is_special
or entry
.name
== '__getattribute__':
1903 if entry
.name
not in ['__cinit__', '__dealloc__', '__richcmp__', '__next__', '__getreadbuffer__', '__getwritebuffer__', '__getsegcount__', '__getcharbuffer__', '__getbuffer__', '__releasebuffer__']:
1904 if entry
.name
== '__getattr__' and not self
.globalstate
.directives
['fast_getattr']:
1906 # Python's typeobject.c will automatically fill in our slot
1907 # in add_operators() (called by PyType_Ready) with a value
1908 # that's better than ours.
1911 from TypeSlots
import method_coexist
1913 doc_code
= entry
.doc_cname
1916 method_flags
= entry
.signature
.method_flags()
1918 if entry
.is_special
:
1919 method_flags
+= [method_coexist
]
1921 '{__Pyx_NAMESTR("%s"), (PyCFunction)%s, %s, __Pyx_DOCSTR(%s)}%s' % (
1924 "|".join(method_flags
),
1930 def put_ensure_gil(self
, declare_gilstate
=True, variable
=None):
1932 Acquire the GIL. The generated code is safe even when no PyThreadState
1933 has been allocated for this thread (for threads not initialized by
1934 using the Python API). Additionally, the code generated by this method
1935 may be called recursively.
1937 self
.globalstate
.use_utility_code(
1938 UtilityCode
.load_cached("ForceInitThreads", "ModuleSetupCode.c"))
1939 self
.putln("#ifdef WITH_THREAD")
1941 variable
= '__pyx_gilstate_save'
1942 if declare_gilstate
:
1943 self
.put("PyGILState_STATE ")
1944 self
.putln("%s = PyGILState_Ensure();" % variable
)
1945 self
.putln("#endif")
1947 def put_release_ensured_gil(self
, variable
=None):
1949 Releases the GIL, corresponds to `put_ensure_gil`.
1952 variable
= '__pyx_gilstate_save'
1953 self
.putln("#ifdef WITH_THREAD")
1954 self
.putln("PyGILState_Release(%s);" % variable
)
1955 self
.putln("#endif")
1957 def put_acquire_gil(self
, variable
=None):
1959 Acquire the GIL. The thread's thread state must have been initialized
1960 by a previous `put_release_gil`
1962 self
.putln("#ifdef WITH_THREAD")
1964 self
.putln('_save = %s;' % variable
)
1965 self
.putln("Py_BLOCK_THREADS")
1966 self
.putln("#endif")
1968 def put_release_gil(self
, variable
=None):
1969 "Release the GIL, corresponds to `put_acquire_gil`."
1970 self
.putln("#ifdef WITH_THREAD")
1971 self
.putln("PyThreadState *_save;")
1972 self
.putln("Py_UNBLOCK_THREADS")
1974 self
.putln('%s = _save;' % variable
)
1975 self
.putln("#endif")
1977 def declare_gilstate(self
):
1978 self
.putln("#ifdef WITH_THREAD")
1979 self
.putln("PyGILState_STATE __pyx_gilstate_save;")
1980 self
.putln("#endif")
1984 def put_error_if_neg(self
, pos
, value
):
1985 # return self.putln("if (unlikely(%s < 0)) %s" % (value, self.error_goto(pos))) # TODO this path is almost _never_ taken, yet this macro makes is slower!
1986 return self
.putln("if (%s < 0) %s" % (value
, self
.error_goto(pos
)))
1988 def put_error_if_unbound(self
, pos
, entry
, in_nogil_context
=False):
1990 if entry
.from_closure
:
1991 func
= '__Pyx_RaiseClosureNameError'
1992 self
.globalstate
.use_utility_code(
1993 ExprNodes
.raise_closure_name_error_utility_code
)
1994 elif entry
.type.is_memoryviewslice
and in_nogil_context
:
1995 func
= '__Pyx_RaiseUnboundMemoryviewSliceNogil'
1996 self
.globalstate
.use_utility_code(
1997 ExprNodes
.raise_unbound_memoryview_utility_code_nogil
)
1999 func
= '__Pyx_RaiseUnboundLocalError'
2000 self
.globalstate
.use_utility_code(
2001 ExprNodes
.raise_unbound_local_error_utility_code
)
2003 self
.putln('if (unlikely(!%s)) { %s("%s"); %s }' % (
2004 entry
.type.check_for_null_code(entry
.cname
),
2007 self
.error_goto(pos
)))
2009 def set_error_info(self
, pos
, used
=False):
2010 self
.funcstate
.should_declare_error_indicator
= True
2012 self
.funcstate
.uses_error_indicator
= True
2013 if self
.c_line_in_traceback
:
2014 cinfo
= " %s = %s;" % (Naming
.clineno_cname
, Naming
.line_c_macro
)
2018 return "%s = %s[%s]; %s = %s;%s" % (
2019 Naming
.filename_cname
,
2020 Naming
.filetable_cname
,
2021 self
.lookup_filename(pos
[0]),
2022 Naming
.lineno_cname
,
2026 def error_goto(self
, pos
):
2027 lbl
= self
.funcstate
.error_label
2028 self
.funcstate
.use_label(lbl
)
2029 return "{%s goto %s;}" % (
2030 self
.set_error_info(pos
),
2033 def error_goto_if(self
, cond
, pos
):
2034 return "if (%s) %s" % (self
.unlikely(cond
), self
.error_goto(pos
))
2036 def error_goto_if_null(self
, cname
, pos
):
2037 return self
.error_goto_if("!%s" % cname
, pos
)
2039 def error_goto_if_neg(self
, cname
, pos
):
2040 return self
.error_goto_if("%s < 0" % cname
, pos
)
2042 def error_goto_if_PyErr(self
, pos
):
2043 return self
.error_goto_if("PyErr_Occurred()", pos
)
2045 def lookup_filename(self
, filename
):
2046 return self
.globalstate
.lookup_filename(filename
)
2048 def put_declare_refcount_context(self
):
2049 self
.putln('__Pyx_RefNannyDeclarations')
2051 def put_setup_refcount_context(self
, name
, acquire_gil
=False):
2053 self
.globalstate
.use_utility_code(
2054 UtilityCode
.load_cached("ForceInitThreads", "ModuleSetupCode.c"))
2055 self
.putln('__Pyx_RefNannySetupContext("%s", %d);' % (name
, acquire_gil
and 1 or 0))
2057 def put_finish_refcount_context(self
):
2058 self
.putln("__Pyx_RefNannyFinishContext();")
2060 def put_add_traceback(self
, qualified_name
):
2062 Build a Python traceback for propagating exceptions.
2064 qualified_name should be the qualified name of the function.
2068 Naming
.clineno_cname
,
2069 Naming
.lineno_cname
,
2070 Naming
.filename_cname
,
2072 self
.funcstate
.uses_error_indicator
= True
2073 self
.putln('__Pyx_AddTraceback("%s", %s, %s, %s);' % format_tuple
)
2075 def put_unraisable(self
, qualified_name
):
2077 Generate code to print a Python warning for an unraisable exception.
2079 qualified_name should be the qualified name of the function.
2083 Naming
.clineno_cname
,
2084 Naming
.lineno_cname
,
2085 Naming
.filename_cname
,
2086 int(self
.globalstate
.directives
['unraisable_tracebacks'])
2088 self
.funcstate
.uses_error_indicator
= True
2089 self
.putln('__Pyx_WriteUnraisable("%s", %s, %s, %s, %s);' % format_tuple
)
2090 self
.globalstate
.use_utility_code(
2091 UtilityCode
.load_cached("WriteUnraisableException", "Exceptions.c"))
2093 def put_trace_declarations(self
):
2094 self
.putln('__Pyx_TraceDeclarations')
2096 def put_trace_call(self
, name
, pos
):
2097 self
.putln('__Pyx_TraceCall("%s", %s[%s], %s);' % (name
, Naming
.filetable_cname
, self
.lookup_filename(pos
[0]), pos
[1]))
2099 def put_trace_exception(self
):
2100 self
.putln("__Pyx_TraceException();")
2102 def put_trace_return(self
, retvalue_cname
):
2103 self
.putln("__Pyx_TraceReturn(%s);" % retvalue_cname
)
2105 def putln_openmp(self
, string
):
2106 self
.putln("#ifdef _OPENMP")
2108 self
.putln("#endif /* _OPENMP */")
2110 def undef_builtin_expect(self
, cond
):
2112 Redefine the macros likely() and unlikely to no-ops, depending on
2115 self
.putln("#if %s" % cond
)
2116 self
.putln(" #undef likely")
2117 self
.putln(" #undef unlikely")
2118 self
.putln(" #define likely(x) (x)")
2119 self
.putln(" #define unlikely(x) (x)")
2120 self
.putln("#endif")
2122 def redef_builtin_expect(self
, cond
):
2123 self
.putln("#if %s" % cond
)
2124 self
.putln(" #undef likely")
2125 self
.putln(" #undef unlikely")
2126 self
.putln(" #define likely(x) __builtin_expect(!!(x), 1)")
2127 self
.putln(" #define unlikely(x) __builtin_expect(!!(x), 0)")
2128 self
.putln("#endif")
2130 class PyrexCodeWriter(object):
2131 # f file output file
2132 # level int indentation level
2134 def __init__(self
, outfile_name
):
2135 self
.f
= Utils
.open_new_file(outfile_name
)
2138 def putln(self
, code
):
2139 self
.f
.write("%s%s\n" % (" " * self
.level
, code
))
2147 class PyxCodeWriter(object):
2149 Can be used for writing out some Cython code. To use the indenter
2150 functionality, the Cython.Compiler.Importer module will have to be used
2151 to load the code to support python 2.4
2154 def __init__(self
, buffer=None, indent_level
=0, context
=None, encoding
='ascii'):
2155 self
.buffer = buffer or StringIOTree()
2156 self
.level
= indent_level
2157 self
.context
= context
2158 self
.encoding
= encoding
2160 def indent(self
, levels
=1):
2161 self
.level
+= levels
2164 def dedent(self
, levels
=1):
2165 self
.level
-= levels
2167 def indenter(self
, line
):
2171 with pyx_code.indenter("for i in range(10):"):
2172 pyx_code.putln("print i")
2176 if pyx_code.indenter("for i in range(10);"):
2177 pyx_code.putln("print i")
2185 result
= self
.buffer.getvalue()
2186 if not isinstance(result
, unicode):
2187 result
= result
.decode(self
.encoding
)
2191 def putln(self
, line
, context
=None):
2192 context
= context
or self
.context
2194 line
= sub_tempita(line
, context
)
2197 def _putln(self
, line
):
2198 self
.buffer.write("%s%s\n" % (self
.level
* " ", line
))
2200 def put_chunk(self
, chunk
, context
=None):
2201 context
= context
or self
.context
2203 chunk
= sub_tempita(chunk
, context
)
2205 chunk
= textwrap
.dedent(chunk
)
2206 for line
in chunk
.splitlines():
2209 def insertion_point(self
):
2210 return PyxCodeWriter(self
.buffer.insertion_point(), self
.level
,
2213 def named_insertion_point(self
, name
):
2214 setattr(self
, name
, self
.insertion_point())
2217 class ClosureTempAllocator(object):
2218 def __init__(self
, klass
):
2220 self
.temps_allocated
= {}
2221 self
.temps_free
= {}
2222 self
.temps_count
= 0
2225 for type, cnames
in self
.temps_allocated
.items():
2226 self
.temps_free
[type] = list(cnames
)
2228 def allocate_temp(self
, type):
2229 if not type in self
.temps_allocated
:
2230 self
.temps_allocated
[type] = []
2231 self
.temps_free
[type] = []
2232 elif self
.temps_free
[type]:
2233 return self
.temps_free
[type].pop(0)
2234 cname
= '%s%d' % (Naming
.codewriter_temp_prefix
, self
.temps_count
)
2235 self
.klass
.declare_var(pos
=None, name
=cname
, cname
=cname
, type=type, is_cdef
=True)
2236 self
.temps_allocated
[type].append(cname
)
2237 self
.temps_count
+= 1