Code.py 80.3 KB
Newer Older
1
# cython: language_level = 2
William Stein's avatar
William Stein committed
2
#
3
#   Code output module
William Stein's avatar
William Stein committed
4 5
#

6 7
from __future__ import absolute_import

Stefan Behnel's avatar
Stefan Behnel committed
8
import cython
9 10
cython.declare(os=object, re=object, operator=object,
               Naming=object, Options=object, StringEncoding=object,
Stefan Behnel's avatar
Stefan Behnel committed
11
               Utils=object, SourceDescriptor=object, StringIOTree=object,
12
               DebugFlags=object, basestring=object)
Stefan Behnel's avatar
Stefan Behnel committed
13

14
import os
15
import re
Stefan Behnel's avatar
Stefan Behnel committed
16
import sys
17
from string import Template
18
import operator
19
import textwrap
20

Robert Bradshaw's avatar
Robert Bradshaw committed
21 22 23 24 25
try:
    import hashlib
except ImportError:
    import md5 as hashlib

26 27 28 29 30 31 32
from . import Naming
from . import Options
from . import DebugFlags
from . import StringEncoding
from .. import Utils
from .Scanning import SourceDescriptor
from ..StringIOTree import StringIOTree
33

Stefan Behnel's avatar
Stefan Behnel committed
34
try:
Stefan Behnel's avatar
Stefan Behnel committed
35 36 37
    from __builtin__ import basestring
except ImportError:
    from builtins import str as basestring
38

39
KEYWORDS_MUST_BE_BYTES = sys.version_info < (2,7)
Stefan Behnel's avatar
Stefan Behnel committed
40

41 42

non_portable_builtins_map = {
43
    # builtins that have different names in different Python versions
44 45
    'bytes'         : ('PY_MAJOR_VERSION < 3',  'str'),
    'unicode'       : ('PY_MAJOR_VERSION >= 3', 'str'),
46
    'basestring'    : ('PY_MAJOR_VERSION >= 3', 'str'),
47
    'xrange'        : ('PY_MAJOR_VERSION >= 3', 'range'),
48
    'raw_input'     : ('PY_MAJOR_VERSION >= 3', 'input'),
49 50
    }

51 52
basicsize_builtins_map = {
    # builtins whose type has a different tp_basicsize than sizeof(...)
53 54
    'PyTypeObject': 'PyHeapTypeObject',
}
55

56 57 58 59
uncachable_builtins = [
    # builtin names that cannot be cached because they may or may not
    # be available at import time
    'WindowsError',
60 61
    '_',  # e.g. gettext
]
62

63 64 65 66
modifier_output_mapper = {
    'inline': 'CYTHON_INLINE'
}.get

67 68
is_self_assignment = re.compile(r" *(\w+) = (\1);\s*$").match

Stefan Behnel's avatar
Stefan Behnel committed
69

70 71 72 73 74
def get_utility_dir():
    # make this a function and not global variables:
    # http://trac.cython.org/cython_trac/ticket/475
    Cython_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    return os.path.join(Cython_dir, "Utility")
Mark Florisson's avatar
Mark Florisson committed
75

Stefan Behnel's avatar
Stefan Behnel committed
76

77
class UtilityCodeBase(object):
78 79 80 81 82 83
    """
    Support for loading utility code from a file.

    Code sections in the file can be specified as follows:

        ##### MyUtility.proto #####
84

85
        [proto declarations]
86

87
        ##### MyUtility.init #####
88

89
        [code run at module initialization]
90 91 92

        ##### MyUtility #####
        #@requires: MyOtherUtility
93
        #@substitute: naming
94

95
        [definitions]
96 97 98 99 100 101 102 103 104

    for prototypes and implementation respectively.  For non-python or
    -cython files backslashes should be used instead.  5 to 30 comment
    characters may be used on either side.

    If the @cname decorator is not used and this is a CythonUtilityCode,
    one should pass in the 'name' keyword argument to be used for name
    mangling of such entries.
    """
105 106

    is_cython_utility = False
107
    requires = None
108 109
    _utility_cache = {}

110
    @classmethod
111
    def _add_utility(cls, utility, type, lines, begin_lineno, tags=None):
112 113
        if utility is None:
            return
114

115 116 117 118 119 120 121 122 123 124 125
        code = '\n'.join(lines)
        if tags and 'substitute' in tags and tags['substitute'] == set(['naming']):
            del tags['substitute']
            try:
                code = Template(code).substitute(vars(Naming))
            except (KeyError, ValueError), e:
                raise RuntimeError("Error parsing templated utility code of type '%s' at line %d: %s" % (
                    type, begin_lineno, e))

        # remember correct line numbers at least until after templating
        code = '\n' * begin_lineno + code
126

127
        if type == 'proto':
128
            utility[0] = code
129
        elif type == 'impl':
130
            utility[1] = code
131 132
        else:
            all_tags = utility[2]
Stefan Behnel's avatar
Py2 fix  
Stefan Behnel committed
133 134
            if KEYWORDS_MUST_BE_BYTES:
                type = type.encode('ASCII')
135
            all_tags[type] = code
136

137 138
        if tags:
            all_tags = utility[2]
Stefan Behnel's avatar
Stefan Behnel committed
139
            for name, values in tags.items():
Stefan Behnel's avatar
Stefan Behnel committed
140 141
                if KEYWORDS_MUST_BE_BYTES:
                    name = name.encode('ASCII')
142
                all_tags.setdefault(name, set()).update(values)
143

144
    @classmethod
145 146 147 148 149
    def load_utilities_from_file(cls, path):
        utilities = cls._utility_cache.get(path)
        if utilities:
            return utilities

150
        filename = os.path.join(get_utility_dir(), path)
151 152 153
        _, ext = os.path.splitext(path)
        if ext in ('.pyx', '.py', '.pxd', '.pxi'):
            comment = '#'
154
            replace_comments = re.compile(r'^\s*#.*').sub
155
        else:
156
            comment = '/'
157
            replace_comments = re.compile(r'^\s*//.*|/\*[^*]*\*/').sub
158
        match_special = re.compile(
159
            (r'^%(C)s{5,30}\s*(?P<name>(?:\w|\.)+)\s*%(C)s{5,30}|'
Stefan Behnel's avatar
Stefan Behnel committed
160
             r'^%(C)s+@(?P<tag>\w+)\s*:\s*(?P<value>(?:\w|[.:])+)'
161
                ) % {'C':comment}).match
162
        match_type = re.compile('(.+)[.](proto|impl|init|cleanup)$').match
163

164 165
        f = Utils.open_source_file(filename, encoding='UTF-8')
        try:
166
            all_lines = f.readlines()
167 168
        finally:
            f.close()
169

170 171
        utilities = {}
        lines = []
172
        tags = {}
173 174 175
        utility = type = None
        begin_lineno = 0

Mark Florisson's avatar
Mark Florisson committed
176
        for lineno, line in enumerate(all_lines):
177
            m = match_special(line)
Mark Florisson's avatar
Mark Florisson committed
178
            if m:
179
                if m.group('name'):
180 181 182 183 184 185
                    cls._add_utility(utility, type, lines, begin_lineno, tags)

                    begin_lineno = lineno + 1
                    del lines[:]
                    tags.clear()

186 187 188 189
                    name = m.group('name')
                    mtype = match_type(name)
                    if mtype:
                        name, type = mtype.groups()
190
                    else:
191
                        type = 'impl'
192
                    utility = utilities.setdefault(name, [None, None, {}])
Mark Florisson's avatar
Mark Florisson committed
193
                else:
194
                    tags.setdefault(m.group('tag'), set()).add(m.group('value'))
195
                    lines.append('') # keep line number correct
Mark Florisson's avatar
Mark Florisson committed
196
            else:
197
                lines.append(replace_comments('', line).rstrip())
Mark Florisson's avatar
Mark Florisson committed
198

199
        if utility is None:
200 201 202
            raise ValueError("Empty utility code file")

        # Don't forget to add the last utility code
203
        cls._add_utility(utility, type, lines, begin_lineno, tags)
204 205 206 207

        cls._utility_cache[path] = utilities
        return utilities

208
    @classmethod
209
    def load(cls, util_code_name, from_file=None, **kwargs):
210
        """
211 212 213 214
        Load utility code from a file specified by from_file (relative to
        Cython/Utility) and name util_code_name.  If from_file is not given,
        load it from the file util_code_name.*.  There should be only one
        file matched by this pattern.
215
        """
216 217 218
        if '::' in util_code_name:
            from_file, util_code_name = util_code_name.rsplit('::', 1)
        if not from_file:
219 220
            utility_dir = get_utility_dir()
            prefix = util_code_name + '.'
221 222 223 224 225 226 227 228 229 230 231 232 233 234
            try:
                listing = os.listdir(utility_dir)
            except OSError:
                # XXX the code below assumes as 'zipimport.zipimporter' instance
                # XXX should be easy to generalize, but too lazy right now to write it
                import zipfile
                global __loader__
                loader = __loader__
                archive = loader.archive
                fileobj = zipfile.ZipFile(archive)
                listing = [ os.path.basename(name)
                            for name in fileobj.namelist()
                            if os.path.join(archive, name).startswith(utility_dir)]
                fileobj.close()
235
            files = [ os.path.join(utility_dir, filename)
236
                      for filename in listing
237 238 239 240 241 242
                      if filename.startswith(prefix) ]
            if not files:
                raise ValueError("No match found for utility code " + util_code_name)
            if len(files) > 1:
                raise ValueError("More than one filename match found for utility code " + util_code_name)
            from_file = files[0]
243 244

        utilities = cls.load_utilities_from_file(from_file)
245 246 247 248
        proto, impl, tags = utilities[util_code_name]

        if tags:
            orig_kwargs = kwargs.copy()
Stefan Behnel's avatar
Stefan Behnel committed
249
            for name, values in tags.items():
250 251 252 253
                if name in kwargs:
                    continue
                # only pass lists when we have to: most argument expect one value or None
                if name == 'requires':
254 255 256 257 258 259 260
                    if orig_kwargs:
                        values = [cls.load(dep, from_file, **orig_kwargs)
                                  for dep in sorted(values)]
                    else:
                        # dependencies are rarely unique, so use load_cached() when we can
                        values = [cls.load_cached(dep, from_file)
                                  for dep in sorted(values)]
261 262 263 264 265
                elif not values:
                    values = None
                elif len(values) == 1:
                    values = values[0]
                kwargs[name] = values
Mark Florisson's avatar
Mark Florisson committed
266

267 268 269 270
        if proto is not None:
            kwargs['proto'] = proto
        if impl is not None:
            kwargs['impl'] = impl
Mark Florisson's avatar
Mark Florisson committed
271

272 273
        if 'name' not in kwargs:
            kwargs['name'] = util_code_name
Mark Florisson's avatar
Mark Florisson committed
274

275 276 277 278 279
        if 'file' not in kwargs and from_file:
            kwargs['file'] = from_file
        return cls(**kwargs)

    @classmethod
280
    def load_cached(cls, utility_code_name, from_file=None, __cache={}):
281
        """
282
        Calls .load(), but using a per-type cache based on utility name and file name.
283
        """
284 285
        key = (cls, from_file, utility_code_name)
        try:
286
            return __cache[key]
287 288
        except KeyError:
            pass
289
        code = __cache[key] = cls.load(utility_code_name, from_file)
290
        return code
291

292 293 294 295 296 297 298
    @classmethod
    def load_as_string(cls, util_code_name, from_file=None, **kwargs):
        """
        Load a utility code as a string. Returns (proto, implementation)
        """
        util = cls.load(util_code_name, from_file, **kwargs)
        proto, impl = util.proto, util.impl
299
        return util.format_code(proto), util.format_code(impl)
300

301
    def format_code(self, code_string, replace_empty_lines=re.compile(r'\n\n+').sub):
302 303 304 305 306 307 308
        """
        Format a code section for output.
        """
        if code_string:
            code_string = replace_empty_lines('\n', code_string.strip()) + '\n\n'
        return code_string

309 310 311
    def __str__(self):
        return "<%s(%s)" % (type(self).__name__, self.name)

312 313
    def get_tree(self):
        pass
314

Stefan Behnel's avatar
Stefan Behnel committed
315

316
class UtilityCode(UtilityCodeBase):
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
    """
    Stores utility code to add during code generation.

    See GlobalState.put_utility_code.

    hashes/equals by instance

    proto           C prototypes
    impl            implemenation code
    init            code to call on module initialization
    requires        utility code dependencies
    proto_block     the place in the resulting file where the prototype should
                    end up
    name            name of the utility code (or None)
    file            filename of the utility code file this utility was loaded
                    from (or None)
    """
Robert Bradshaw's avatar
Robert Bradshaw committed
334

Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
335
    def __init__(self, proto=None, impl=None, init=None, cleanup=None, requires=None,
336
                 proto_block='utility_code_proto', name=None, file=None):
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
337
        # proto_block: Which code block to dump prototype in. See GlobalState.
338 339 340 341 342 343 344
        self.proto = proto
        self.impl = impl
        self.init = init
        self.cleanup = cleanup
        self.requires = requires
        self._cache = {}
        self.specialize_list = []
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
345
        self.proto_block = proto_block
346
        self.name = name
347
        self.file = file
348

349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
    def __hash__(self):
        return hash((self.proto, self.impl))

    def __eq__(self, other):
        if self is other:
            return True
        if not isinstance(other, type(self)):
            return False

        self_proto = getattr(self, 'proto', None)
        other_proto = getattr(other, 'proto', None)
        return (self_proto, self.impl) == (other_proto, other.impl)

    def none_or_sub(self, s, context):
        """
        Format a string in this utility code with context. If None, do nothing.
        """
        if s is None:
            return None
        return s % context

    def specialize(self, pyrex_type=None, **data):
371 372
        # Dicts aren't hashable...
        if pyrex_type is not None:
373
            data['type'] = pyrex_type.empty_declaration_code()
Craig Citro's avatar
Craig Citro committed
374
            data['type_name'] = pyrex_type.specialization_name()
Stefan Behnel's avatar
Stefan Behnel committed
375
        key = tuple(sorted(data.items()))
376 377 378 379 380 381 382
        try:
            return self._cache[key]
        except KeyError:
            if self.requires is None:
                requires = None
            else:
                requires = [r.specialize(data) for r in self.requires]
383

384
            s = self._cache[key] = UtilityCode(
385 386 387 388
                    self.none_or_sub(self.proto, data),
                    self.none_or_sub(self.impl, data),
                    self.none_or_sub(self.init, data),
                    self.none_or_sub(self.cleanup, data),
389 390 391
                    requires,
                    self.proto_block)

392 393 394
            self.specialize_list.append(s)
            return s

395 396 397
    def inject_string_constants(self, impl, output):
        """Replace 'PYIDENT("xyz")' by a constant Python identifier cname.
        """
398 399 400 401 402 403 404 405 406 407 408 409
        replacements = {}
        def externalise(matchobj):
            name = matchobj.group(1)
            try:
                cname = replacements[name]
            except KeyError:
                cname = replacements[name] = output.get_interned_identifier(
                    StringEncoding.EncodedString(name)).cname
            return cname

        impl = re.sub('PYIDENT\("([^"]+)"\)', externalise, impl)
        return bool(replacements), impl
410

411 412 413 414 415
    def put_code(self, output):
        if self.requires:
            for dependency in self.requires:
                output.use_utility_code(dependency)
        if self.proto:
416 417 418
            output[self.proto_block].put_or_include(
                self.format_code(self.proto),
                '%s_proto' % self.name)
419
        if self.impl:
420 421 422 423 424 425 426 427
            impl = self.format_code(self.impl)
            is_specialised, impl = self.inject_string_constants(impl, output)
            if not is_specialised:
                # no module specific adaptations => can be reused
                output['utility_code_def'].put_or_include(
                    impl, '%s_impl' % self.name)
            else:
                output['utility_code_def'].put(impl)
428 429
        if self.init:
            writer = output['init_globals']
430
            writer.putln("/* %s.init */" % self.name)
431
            if isinstance(self.init, basestring):
432
                writer.put(self.format_code(self.init))
433 434
            else:
                self.init(writer, output.module_pos)
435 436
            writer.putln(writer.error_goto_if_PyErr(output.module_pos))
            writer.putln()
437 438 439
        if self.cleanup and Options.generate_cleanup_code:
            writer = output['cleanup_globals']
            if isinstance(self.cleanup, basestring):
440 441 442
                writer.put_or_include(
                    self.format_code(self.cleanup),
                    '%s_cleanup' % self.name)
443 444
            else:
                self.cleanup(writer, output.module_pos)
Robert Bradshaw's avatar
Robert Bradshaw committed
445 446


447
def sub_tempita(s, context, file=None, name=None):
448 449 450
    "Run tempita on string s with given context."
    if not s:
        return None
451

452 453 454 455
    if file:
        context['__name'] = "%s:%s" % (file, name)
    elif name:
        context['__name'] = name
456

457
    from ..Tempita import sub
458
    return sub(s, **context)
459

460
class TempitaUtilityCode(UtilityCode):
461
    def __init__(self, name=None, proto=None, impl=None, init=None, file=None, context=None, **kwargs):
462 463
        if context is None:
            context = {}
464 465
        proto = sub_tempita(proto, context, file, name)
        impl = sub_tempita(impl, context, file, name)
466
        init = sub_tempita(init, context, file, name)
467
        super(TempitaUtilityCode, self).__init__(
468
            proto, impl, init=init, name=name, file=file, **kwargs)
469 470 471 472 473 474 475 476

    def none_or_sub(self, s, context):
        """
        Format a string in this utility code with context. If None, do nothing.
        """
        if s is None:
            return None
        return sub_tempita(s, context, self.file, self.name)
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491


class LazyUtilityCode(UtilityCodeBase):
    """
    Utility code that calls a callback with the root code writer when
    available. Useful when you only have 'env' but not 'code'.
    """

    def __init__(self, callback):
        self.callback = callback

    def put_code(self, globalstate):
        utility = self.callback(globalstate.rootwriter)
        globalstate.use_utility_code(utility)

492

493 494 495 496 497 498 499 500 501
class FunctionState(object):
    # return_label     string          function return point label
    # error_label      string          error catch point label
    # continue_label   string          loop continue point label
    # break_label      string          loop break point label
    # return_from_error_cleanup_label string
    # label_counter    integer         counter for naming labels
    # in_try_finally   boolean         inside try of try...finally
    # exc_vars         (string * 3)    exception variables for reraise, or None
502
    # can_trace        boolean         line tracing is supported in the current context
503

504
    # Not used for now, perhaps later
Robert Bradshaw's avatar
Robert Bradshaw committed
505
    def __init__(self, owner, names_taken=set()):
506
        self.names_taken = names_taken
507
        self.owner = owner
Robert Bradshaw's avatar
Robert Bradshaw committed
508

509 510
        self.error_label = None
        self.label_counter = 0
Robert Bradshaw's avatar
Robert Bradshaw committed
511
        self.labels_used = set()
512 513 514 515
        self.return_label = self.new_label()
        self.new_error_label()
        self.continue_label = None
        self.break_label = None
516
        self.yield_labels = []
517

518 519
        self.in_try_finally = 0
        self.exc_vars = None
520
        self.can_trace = False
521
        self.gil_owned = True
522

523
        self.temps_allocated = [] # of (name, type, manage_ref, static)
524 525
        self.temps_free = {} # (type, manage_ref) -> list of free vars with same type/managed status
        self.temps_used_type = {} # name -> (type, manage_ref)
526
        self.temp_counter = 0
527
        self.closure_temps = None
528

529 530 531 532
        # This is used to collect temporaries, useful to find out which temps
        # need to be privatized in parallel sections
        self.collect_temps_stack = []

533 534 535 536 537
        # This is used for the error indicator, which needs to be local to the
        # function. It used to be global, which relies on the GIL being held.
        # However, exceptions may need to be propagated through 'nogil'
        # sections, in which case we introduce a race condition.
        self.should_declare_error_indicator = False
538
        self.uses_error_indicator = False
539

540 541
    # labels

542
    def new_label(self, name=None):
543 544
        n = self.label_counter
        self.label_counter = n + 1
545 546 547 548
        label = "%s%d" % (Naming.label_prefix, n)
        if name is not None:
            label += '_' + name
        return label
Robert Bradshaw's avatar
Robert Bradshaw committed
549

550 551 552 553 554 555
    def new_yield_label(self):
        label = self.new_label('resume_from_yield')
        num_and_label = (len(self.yield_labels) + 1, label)
        self.yield_labels.append(num_and_label)
        return num_and_label

556 557
    def new_error_label(self):
        old_err_lbl = self.error_label
558
        self.error_label = self.new_label('error')
559
        return old_err_lbl
Robert Bradshaw's avatar
Robert Bradshaw committed
560

561 562 563 564
    def get_loop_labels(self):
        return (
            self.continue_label,
            self.break_label)
Robert Bradshaw's avatar
Robert Bradshaw committed
565

566 567 568
    def set_loop_labels(self, labels):
        (self.continue_label,
         self.break_label) = labels
Robert Bradshaw's avatar
Robert Bradshaw committed
569

570 571 572
    def new_loop_labels(self):
        old_labels = self.get_loop_labels()
        self.set_loop_labels(
Robert Bradshaw's avatar
Robert Bradshaw committed
573
            (self.new_label("continue"),
Robert Bradshaw's avatar
Robert Bradshaw committed
574
             self.new_label("break")))
575
        return old_labels
Robert Bradshaw's avatar
Robert Bradshaw committed
576

577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
    def get_all_labels(self):
        return (
            self.continue_label,
            self.break_label,
            self.return_label,
            self.error_label)

    def set_all_labels(self, labels):
        (self.continue_label,
         self.break_label,
         self.return_label,
         self.error_label) = labels

    def all_new_labels(self):
        old_labels = self.get_all_labels()
        new_labels = []
593
        for old_label, name in zip(old_labels, ['continue', 'break', 'return', 'error']):
594
            if old_label:
595
                new_labels.append(self.new_label(name))
596 597 598 599
            else:
                new_labels.append(old_label)
        self.set_all_labels(new_labels)
        return old_labels
Robert Bradshaw's avatar
Robert Bradshaw committed
600

601
    def use_label(self, lbl):
Stefan Behnel's avatar
Stefan Behnel committed
602
        self.labels_used.add(lbl)
Robert Bradshaw's avatar
Robert Bradshaw committed
603

604 605 606
    def label_used(self, lbl):
        return lbl in self.labels_used

607 608
    # temp handling

609
    def allocate_temp(self, type, manage_ref, static=False):
610 611 612 613 614
        """
        Allocates a temporary (which may create a new one or get a previously
        allocated and released one of the same type). Type is simply registered
        and handed back, but will usually be a PyrexType.

615 616 617 618 619
        If type.is_pyobject, manage_ref comes into play. If manage_ref is set to
        True, the temp will be decref-ed on return statements and in exception
        handling clauses. Otherwise the caller has to deal with any reference
        counting of the variable.

620 621 622 623
        If not type.is_pyobject, then manage_ref will be ignored, but it
        still has to be passed. It is recommended to pass False by convention
        if it is known that type will never be a Python object.

624 625 626 627
        static=True marks the temporary declaration with "static".
        This is only used when allocating backing store for a module-level
        C array literals.

628 629
        A C string referring to the variable is returned.
        """
630 631
        if type.is_const:
            type = type.const_base_type
632
        if not type.is_pyobject and not type.is_memoryviewslice:
633 634 635
            # Make manage_ref canonical, so that manage_ref will always mean
            # a decref is needed.
            manage_ref = False
636

637
        freelist = self.temps_free.get((type, manage_ref))
638
        if freelist is not None and len(freelist) > 0:
639
            result = freelist.pop()
640
        else:
641 642 643 644
            while True:
                self.temp_counter += 1
                result = "%s%d" % (Naming.codewriter_temp_prefix, self.temp_counter)
                if not result in self.names_taken: break
645
            self.temps_allocated.append((result, type, manage_ref, static))
646
        self.temps_used_type[result] = (type, manage_ref)
647
        if DebugFlags.debug_temp_code_comments:
648
            self.owner.putln("/* %s allocated (%s) */" % (result, type))
649 650 651 652

        if self.collect_temps_stack:
            self.collect_temps_stack[-1].add((result, type))

653 654 655 656 657 658 659
        return result

    def release_temp(self, name):
        """
        Releases a temporary so that it can be reused by other code needing
        a temp of the same type.
        """
660 661
        type, manage_ref = self.temps_used_type[name]
        freelist = self.temps_free.get((type, manage_ref))
662 663
        if freelist is None:
            freelist = []
664
            self.temps_free[(type, manage_ref)] = freelist
665 666
        if name in freelist:
            raise RuntimeError("Temp %s freed twice!" % name)
667
        freelist.append(name)
668 669
        if DebugFlags.debug_temp_code_comments:
            self.owner.putln("/* %s released */" % name)
670

671
    def temps_in_use(self):
672
        """Return a list of (cname,type,manage_ref) tuples of temp names and their type
673 674 675
        that are currently in use.
        """
        used = []
676
        for name, type, manage_ref, static in self.temps_allocated:
677
            freelist = self.temps_free.get((type, manage_ref))
678
            if freelist is None or name not in freelist:
679
                used.append((name, type, manage_ref and type.is_pyobject))
680 681
        return used

682
    def temps_holding_reference(self):
683
        """Return a list of (cname,type) tuples of temp names and their type
684 685
        that are currently in use. This includes only temps of a
        Python object type which owns its reference.
686 687
        """
        return [(name, type)
688
                for name, type, manage_ref in self.temps_in_use()
689
                if manage_ref  and type.is_pyobject]
690 691 692 693 694

    def all_managed_temps(self):
        """Return a list of (cname, type) tuples of refcount-managed Python objects.
        """
        return [(cname, type)
695
                    for cname, type, manage_ref, static in self.temps_allocated
696
                        if manage_ref]
697

698 699 700 701 702 703 704
    def all_free_managed_temps(self):
        """Return a list of (cname, type) tuples of refcount-managed Python
        objects that are not currently in use.  This is used by
        try-except and try-finally blocks to clean up temps in the
        error case.
        """
        return [(cname, type)
705 706 707
                    for (type, manage_ref), freelist in self.temps_free.items()
                        if manage_ref
                            for cname in freelist]
708

709 710 711 712
    def start_collecting_temps(self):
        """
        Useful to find out which temps were used in a code block
        """
Robert Bradshaw's avatar
Robert Bradshaw committed
713
        self.collect_temps_stack.append(set())
714 715 716

    def stop_collecting_temps(self):
        return self.collect_temps_stack.pop()
717

718 719 720
    def init_closure_temps(self, scope):
        self.closure_temps = ClosureTempAllocator(scope)

721

Stefan Behnel's avatar
Stefan Behnel committed
722 723 724 725 726 727 728
class NumConst(object):
    """Global info about a Python number constant held by GlobalState.

    cname       string
    value       string
    py_type     string     int, long, float
    value_code  string     evaluation code if different from value
729 730
    """

Stefan Behnel's avatar
Stefan Behnel committed
731
    def __init__(self, cname, value, py_type, value_code=None):
732 733
        self.cname = cname
        self.value = value
Stefan Behnel's avatar
Stefan Behnel committed
734 735 736
        self.py_type = py_type
        self.value_code = value_code or value

737

738 739 740 741 742 743 744 745 746 747
class PyObjectConst(object):
    """Global info about a generic constant held by GlobalState.
    """
    # cname       string
    # type        PyrexType

    def __init__(self, cname, type):
        self.cname = cname
        self.type = type

Stefan Behnel's avatar
Stefan Behnel committed
748

749
cython.declare(possible_unicode_identifier=object, possible_bytes_identifier=object,
750
               replace_identifier=object, find_alphanums=object)
Stefan Behnel's avatar
Stefan Behnel committed
751 752
possible_unicode_identifier = re.compile(ur"(?![0-9])\w+$", re.U).match
possible_bytes_identifier = re.compile(r"(?![0-9])\w+$".encode('ASCII')).match
753
replace_identifier = re.compile(r'[^a-zA-Z0-9_]+').sub
754
find_alphanums = re.compile('([a-zA-Z0-9]+)').findall
755 756 757 758 759 760 761 762 763 764 765 766 767

class StringConst(object):
    """Global info about a C string constant held by GlobalState.
    """
    # cname            string
    # text             EncodedString or BytesLiteral
    # py_strings       {(identifier, encoding) : PyStringConst}

    def __init__(self, cname, text, byte_string):
        self.cname = cname
        self.text = text
        self.escaped_value = StringEncoding.escape_byte_string(byte_string)
        self.py_strings = None
768 769 770
        self.py_versions = []

    def add_py_version(self, version):
771 772 773
        if not version:
            self.py_versions = [2,3]
        elif version not in self.py_versions:
774
            self.py_versions.append(version)
775

776 777
    def get_py_string_const(self, encoding, identifier=None,
                            is_str=False, py3str_cstring=None):
778 779 780
        py_strings = self.py_strings
        text = self.text

Stefan Behnel's avatar
Stefan Behnel committed
781
        is_str = bool(identifier or is_str)
782
        is_unicode = encoding is None and not is_str
783

784 785 786 787 788 789 790 791 792 793 794 795
        if encoding is None:
            # unicode string
            encoding_key = None
        else:
            # bytes or str
            encoding = encoding.lower()
            if encoding in ('utf8', 'utf-8', 'ascii', 'usascii', 'us-ascii'):
                encoding = None
                encoding_key = None
            else:
                encoding_key = ''.join(find_alphanums(encoding))

796 797 798 799 800 801
        key = (is_str, is_unicode, encoding_key, py3str_cstring)
        if py_strings is not None:
            try:
                return py_strings[key]
            except KeyError:
                pass
802
        else:
803
            self.py_strings = {}
804

805 806 807 808 809 810 811 812 813 814
        if identifier:
            intern = True
        elif identifier is None:
            if isinstance(text, unicode):
                intern = bool(possible_unicode_identifier(text))
            else:
                intern = bool(possible_bytes_identifier(text))
        else:
            intern = False
        if intern:
815
            prefix = Naming.interned_prefixes['str']
816 817
        else:
            prefix = Naming.py_const_prefix
818 819 820 821 822 823 824

        if encoding_key:
            encoding_prefix = '_%s' % encoding_key
        else:
            encoding_prefix = ''

        pystring_cname = "%s%s%s_%s" % (
825 826
            prefix,
            (is_str and 's') or (is_unicode and 'u') or 'b',
827
            encoding_prefix,
828 829 830 831 832
            self.cname[len(Naming.const_prefix):])

        py_string = PyStringConst(
            pystring_cname, encoding, is_unicode, is_str, py3str_cstring, intern)
        self.py_strings[key] = py_string
833 834 835 836 837 838
        return py_string

class PyStringConst(object):
    """Global info about a Python string constant held by GlobalState.
    """
    # cname       string
839
    # py3str_cstring string
840
    # encoding    string
841
    # intern      boolean
842 843
    # is_unicode  boolean
    # is_str      boolean
844

845 846
    def __init__(self, cname, encoding, is_unicode, is_str=False,
                 py3str_cstring=None, intern=False):
847
        self.cname = cname
848
        self.py3str_cstring = py3str_cstring
849 850 851
        self.encoding = encoding
        self.is_str = is_str
        self.is_unicode = is_unicode
852 853
        self.intern = intern

Stefan Behnel's avatar
Stefan Behnel committed
854 855 856
    def __lt__(self, other):
        return self.cname < other.cname

857

858 859 860 861 862 863
class GlobalState(object):
    # filename_table   {string : int}  for finding filename table indexes
    # filename_list    [string]        filenames in filename table order
    # input_file_contents dict         contents (=list of lines) of any file that was used as input
    #                                  to create this output C code.  This is
    #                                  used to annotate the comments.
864
    #
865
    # utility_codes   set                IDs of used utility code (to avoid reinsertion)
866 867 868 869 870 871
    #
    # declared_cnames  {string:Entry}  used in a transition phase to merge pxd-declared
    #                                  constants etc. into the pyx-declared ones (i.e,
    #                                  check if constants are already added).
    #                                  In time, hopefully the literals etc. will be
    #                                  supplied directly instead.
872
    #
873
    # const_cnames_used  dict          global counter for unique constant identifiers
874
    #
875

876 877
    # parts            {string:CCodeWriter}

Robert Bradshaw's avatar
Robert Bradshaw committed
878

879 880 881 882
    # interned_strings
    # consts
    # interned_nums

883 884 885 886 887 888
    # directives       set             Temporary variable used to track
    #                                  the current set of directives in the code generation
    #                                  process.

    directives = {}

889 890
    code_layout = [
        'h_code',
Robert Bradshaw's avatar
Robert Bradshaw committed
891
        'filename_table',
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
892
        'utility_code_proto_before_types',
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
893 894 895 896
        'numeric_typedefs',          # Let these detailed individual parts stay!,
        'complex_type_declarations', # as the proper solution is to make a full DAG...
        'type_declarations',         # More coarse-grained blocks would simply hide
        'utility_code_proto',        # the ugliness, not fix it
897 898
        'module_declarations',
        'typeinfo',
899 900
        'before_global_var',
        'global_var',
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
901
        'decls',
902
        'all_the_rest',
903 904
        'pystring_table',
        'cached_builtins',
905
        'cached_constants',
906 907 908 909 910
        'init_globals',
        'init_module',
        'cleanup_globals',
        'cleanup_module',
        'main_method',
911 912
        'utility_code_def',
        'end'
913
    ]
Robert Bradshaw's avatar
Robert Bradshaw committed
914

915

916
    def __init__(self, writer, module_node, emit_linenums=False, common_utility_include_dir=None):
917 918 919
        self.filename_table = {}
        self.filename_list = []
        self.input_file_contents = {}
Robert Bradshaw's avatar
Robert Bradshaw committed
920
        self.utility_codes = set()
921
        self.declared_cnames = {}
922
        self.in_utility_code_generation = False
923
        self.emit_linenums = emit_linenums
924
        self.common_utility_include_dir = common_utility_include_dir
925
        self.parts = {}
926 927
        self.module_node = module_node # because some utility code generation needs it
                                       # (generating backwards-compatible Get/ReleaseBuffer
928

929
        self.const_cnames_used = {}
930
        self.string_const_index = {}
Nikita Nemkin's avatar
Nikita Nemkin committed
931
        self.pyunicode_ptr_const_index = {}
Stefan Behnel's avatar
Stefan Behnel committed
932
        self.num_const_index = {}
933
        self.py_constants = []
934

935 936
        assert writer.globalstate is None
        writer.globalstate = self
937
        self.rootwriter = writer
938

939 940 941 942
    def initialize_main_c_code(self):
        rootwriter = self.rootwriter
        for part in self.code_layout:
            self.parts[part] = rootwriter.insertion_point()
943

944 945 946 947 948 949
        if not Options.cache_builtins:
            del self.parts['cached_builtins']
        else:
            w = self.parts['cached_builtins']
            w.enter_cfunc_scope()
            w.putln("static int __Pyx_InitCachedBuiltins(void) {")
950

951 952 953 954
        w = self.parts['cached_constants']
        w.enter_cfunc_scope()
        w.putln("")
        w.putln("static int __Pyx_InitCachedConstants(void) {")
955
        w.put_declare_refcount_context()
956 957
        w.put_setup_refcount_context("__Pyx_InitCachedConstants")

958 959 960 961
        w = self.parts['init_globals']
        w.enter_cfunc_scope()
        w.putln("")
        w.putln("static int __Pyx_InitGlobals(void) {")
962

963 964 965 966 967 968 969
        if not Options.generate_cleanup_code:
            del self.parts['cleanup_globals']
        else:
            w = self.parts['cleanup_globals']
            w.enter_cfunc_scope()
            w.putln("")
            w.putln("static void __Pyx_CleanupGlobals(void) {")
970

971 972 973 974
        code = self.parts['utility_code_proto']
        code.putln("")
        code.putln("/* --- Runtime support code (head) --- */")

975 976 977 978
        code = self.parts['utility_code_def']
        if self.emit_linenums:
            code.write('\n#line 1 "cython_utility"\n')
        code.putln("")
979
        code.putln("/* --- Runtime support code --- */")
980

981
    def finalize_main_c_code(self):
982 983 984 985 986 987
        self.close_global_decls()

        #
        # utility_code_def
        #
        code = self.parts['utility_code_def']
988
        code.put(UtilityCode.load_as_string("TypeConversions", "TypeConversion.c")[1])
989 990
        code.putln("")

991 992 993
    def __getitem__(self, key):
        return self.parts[key]

994 995 996
    #
    # Global constants, interned objects, etc.
    #
997 998
    def close_global_decls(self):
        # This is called when it is known that no more global declarations will
999
        # declared.
1000
        self.generate_const_declarations()
1001
        if Options.cache_builtins:
1002
            w = self.parts['cached_builtins']
1003
            w.putln("return 0;")
1004 1005 1006
            if w.label_used(w.error_label):
                w.put_label(w.error_label)
                w.putln("return -1;")
1007 1008 1009
            w.putln("}")
            w.exit_cfunc_scope()

1010 1011 1012 1013 1014 1015 1016 1017 1018 1019
        w = self.parts['cached_constants']
        w.put_finish_refcount_context()
        w.putln("return 0;")
        if w.label_used(w.error_label):
            w.put_label(w.error_label)
            w.put_finish_refcount_context()
            w.putln("return -1;")
        w.putln("}")
        w.exit_cfunc_scope()

1020
        w = self.parts['init_globals']
1021
        w.putln("return 0;")
1022 1023 1024
        if w.label_used(w.error_label):
            w.put_label(w.error_label)
            w.putln("return -1;")
1025 1026
        w.putln("}")
        w.exit_cfunc_scope()
1027

1028 1029 1030 1031 1032
        if Options.generate_cleanup_code:
            w = self.parts['cleanup_globals']
            w.putln("}")
            w.exit_cfunc_scope()

1033 1034 1035 1036
        if Options.generate_cleanup_code:
            w = self.parts['cleanup_module']
            w.putln("}")
            w.exit_cfunc_scope()
Robert Bradshaw's avatar
Robert Bradshaw committed
1037

1038
    def put_pyobject_decl(self, entry):
1039
        self['global_var'].putln("static PyObject *%s;" % entry.cname)
1040

1041 1042
    # constant handling at code generation time

1043 1044 1045
    def get_cached_constants_writer(self):
        return self.parts['cached_constants']

1046
    def get_int_const(self, str_value, longness=False):
Stefan Behnel's avatar
Stefan Behnel committed
1047
        py_type = longness and 'long' or 'int'
1048
        try:
Stefan Behnel's avatar
Stefan Behnel committed
1049
            c = self.num_const_index[(str_value, py_type)]
1050
        except KeyError:
Stefan Behnel's avatar
Stefan Behnel committed
1051 1052 1053 1054 1055 1056 1057 1058
            c = self.new_num_const(str_value, py_type)
        return c

    def get_float_const(self, str_value, value_code):
        try:
            c = self.num_const_index[(str_value, 'float')]
        except KeyError:
            c = self.new_num_const(str_value, 'float', value_code)
1059 1060
        return c

Stefan Behnel's avatar
Stefan Behnel committed
1061
    def get_py_const(self, type, prefix='', cleanup_level=None):
1062
        # create a new Python object constant
Stefan Behnel's avatar
Stefan Behnel committed
1063
        const = self.new_py_const(type, prefix)
1064
        if cleanup_level is not None \
Stefan Behnel's avatar
Stefan Behnel committed
1065
                and cleanup_level <= Options.generate_cleanup_code:
1066
            cleanup_writer = self.parts['cleanup_globals']
1067
            cleanup_writer.putln('Py_CLEAR(%s);' % const.cname)
1068
        return const
1069

1070
    def get_string_const(self, text, py_version=None):
1071 1072
        # return a C string constant, creating a new one if necessary
        if text.is_unicode:
1073
            byte_string = text.utf8encode()
1074 1075 1076 1077 1078 1079
        else:
            byte_string = text.byteencode()
        try:
            c = self.string_const_index[byte_string]
        except KeyError:
            c = self.new_string_const(text, byte_string)
1080
        c.add_py_version(py_version)
1081 1082
        return c

1083
    def get_pyunicode_ptr_const(self, text):
1084 1085 1086
        # return a Py_UNICODE[] constant, creating a new one if necessary
        assert text.is_unicode
        try:
Nikita Nemkin's avatar
Nikita Nemkin committed
1087
            c = self.pyunicode_ptr_const_index[text]
1088
        except KeyError:
Nikita Nemkin's avatar
Nikita Nemkin committed
1089
            c = self.pyunicode_ptr_const_index[text] = self.new_const_cname()
1090 1091
        return c

1092 1093
    def get_py_string_const(self, text, identifier=None,
                            is_str=False, unicode_value=None):
1094
        # return a Python string constant, creating a new one if necessary
1095 1096
        py3str_cstring = None
        if is_str and unicode_value is not None \
1097
               and unicode_value.utf8encode() != text.byteencode():
1098 1099 1100 1101
            py3str_cstring = self.get_string_const(unicode_value, py_version=3)
            c_string = self.get_string_const(text, py_version=2)
        else:
            c_string = self.get_string_const(text)
1102 1103
        py_string = c_string.get_py_string_const(
            text.encoding, identifier, is_str, py3str_cstring)
1104 1105
        return py_string

1106 1107 1108
    def get_interned_identifier(self, text):
        return self.get_py_string_const(text, identifier=True)

1109
    def new_string_const(self, text, byte_string):
Stefan Behnel's avatar
Stefan Behnel committed
1110
        cname = self.new_string_const_cname(byte_string)
1111 1112 1113 1114
        c = StringConst(cname, text, byte_string)
        self.string_const_index[byte_string] = c
        return c

Stefan Behnel's avatar
Stefan Behnel committed
1115 1116 1117 1118
    def new_num_const(self, value, py_type, value_code=None):
        cname = self.new_num_const_cname(value, py_type)
        c = NumConst(cname, value, py_type, value_code)
        self.num_const_index[(value, py_type)] = c
1119 1120
        return c

Stefan Behnel's avatar
Stefan Behnel committed
1121 1122
    def new_py_const(self, type, prefix=''):
        cname = self.new_const_cname(prefix)
1123 1124 1125 1126
        c = PyObjectConst(cname, type)
        self.py_constants.append(c)
        return c

Stefan Behnel's avatar
Stefan Behnel committed
1127
    def new_string_const_cname(self, bytes_value):
1128
        # Create a new globally-unique nice name for a C string constant.
Stefan Behnel's avatar
Stefan Behnel committed
1129
        value = bytes_value.decode('ASCII', 'ignore')
1130
        return self.new_const_cname(value=value)
1131

Stefan Behnel's avatar
Stefan Behnel committed
1132 1133
    def new_num_const_cname(self, value, py_type):
        if py_type == 'long':
1134
            value += 'L'
1135 1136
            py_type = 'int'
        prefix = Naming.interned_prefixes[py_type]
Stefan Behnel's avatar
Stefan Behnel committed
1137
        cname = "%s%s" % (prefix, value)
1138
        cname = cname.replace('+', '_').replace('-', 'neg_').replace('.', '_')
1139 1140
        return cname

1141 1142
    def new_const_cname(self, prefix='', value=''):
        value = replace_identifier('_', value)[:32].strip('_')
1143 1144 1145
        used = self.const_cnames_used
        name_suffix = value
        while name_suffix in used:
1146
            counter = used[value] = used[value] + 1
1147
            name_suffix = '%s_%d' % (value, counter)
1148
        used[name_suffix] = 1
1149 1150 1151 1152 1153
        if prefix:
            prefix = Naming.interned_prefixes[prefix]
        else:
            prefix = Naming.const_prefix
        return "%s%s" % (prefix, name_suffix)
1154 1155

    def add_cached_builtin_decl(self, entry):
1156
        if entry.is_builtin and entry.is_const:
1157 1158
            if self.should_declare(entry.cname, entry):
                self.put_pyobject_decl(entry)
1159
                w = self.parts['cached_builtins']
1160 1161 1162 1163
                condition = None
                if entry.name in non_portable_builtins_map:
                    condition, replacement = non_portable_builtins_map[entry.name]
                    w.putln('#if %s' % condition)
1164
                    self.put_cached_builtin_init(
1165
                        entry.pos, StringEncoding.EncodedString(replacement),
1166
                        entry.cname)
1167 1168 1169 1170
                    w.putln('#else')
                self.put_cached_builtin_init(
                    entry.pos, StringEncoding.EncodedString(entry.name),
                    entry.cname)
1171
                if condition:
1172 1173 1174 1175 1176
                    w.putln('#endif')

    def put_cached_builtin_init(self, pos, name, cname):
        w = self.parts['cached_builtins']
        interned_cname = self.get_interned_identifier(name).cname
Stefan Behnel's avatar
Stefan Behnel committed
1177 1178 1179
        self.use_utility_code(
            UtilityCode.load_cached("GetBuiltinName", "ObjectHandling.c"))
        w.putln('%s = __Pyx_GetBuiltinName(%s); if (!%s) %s' % (
1180 1181 1182 1183
            cname,
            interned_cname,
            cname,
            w.error_goto(pos)))
1184 1185 1186

    def generate_const_declarations(self):
        self.generate_string_constants()
Stefan Behnel's avatar
Stefan Behnel committed
1187
        self.generate_num_constants()
1188 1189 1190 1191 1192 1193
        self.generate_object_constant_decls()

    def generate_object_constant_decls(self):
        consts = [ (len(c.cname), c.cname, c)
                   for c in self.py_constants ]
        consts.sort()
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
1194
        decls_writer = self.parts['decls']
1195
        for _, cname, c in consts:
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
1196
            decls_writer.putln(
1197
                "static %s;" % c.type.declaration_code(cname))
1198 1199 1200

    def generate_string_constants(self):
        c_consts = [ (len(c.cname), c.cname, c)
Stefan Behnel's avatar
Stefan Behnel committed
1201
                     for c in self.string_const_index.values() ]
1202 1203
        c_consts.sort()
        py_strings = []
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
1204 1205

        decls_writer = self.parts['decls']
1206
        for _, cname, c in c_consts:
1207 1208 1209 1210 1211
            conditional = False
            if c.py_versions and (2 not in c.py_versions or 3 not in c.py_versions):
                conditional = True
                decls_writer.putln("#if PY_MAJOR_VERSION %s 3" % (
                    (2 in c.py_versions) and '<' or '>='))
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
1212
            decls_writer.putln('static char %s[] = "%s";' % (
1213
                cname, StringEncoding.split_string_literal(c.escaped_value)))
1214 1215
            if conditional:
                decls_writer.putln("#endif")
1216
            if c.py_strings is not None:
Stefan Behnel's avatar
Stefan Behnel committed
1217
                for py_string in c.py_strings.values():
1218 1219
                    py_strings.append((c.cname, len(py_string.cname), py_string))

Nikita Nemkin's avatar
Nikita Nemkin committed
1220
        for c, cname in self.pyunicode_ptr_const_index.items():
1221
            utf16_array, utf32_array = StringEncoding.encode_pyunicode_string(c)
1222 1223
            if utf16_array:
                # Narrow and wide representations differ
Nikita Nemkin's avatar
Nikita Nemkin committed
1224
                decls_writer.putln("#ifdef Py_UNICODE_WIDE")
1225 1226 1227 1228 1229
            decls_writer.putln("static Py_UNICODE %s[] = { %s };" % (cname, utf32_array))
            if utf16_array:
                decls_writer.putln("#else")
                decls_writer.putln("static Py_UNICODE %s[] = { %s };" % (cname, utf16_array))
                decls_writer.putln("#endif")
1230

1231
        if py_strings:
1232
            self.use_utility_code(UtilityCode.load_cached("InitStrings", "StringTools.c"))
1233
            py_strings.sort()
1234 1235 1236
            w = self.parts['pystring_table']
            w.putln("")
            w.putln("static __Pyx_StringTabEntry %s[] = {" %
1237 1238
                                      Naming.stringtab_cname)
            for c_cname, _, py_string in py_strings:
1239 1240 1241 1242 1243 1244 1245
                if not py_string.is_str or not py_string.encoding or \
                       py_string.encoding in ('ASCII', 'USASCII', 'US-ASCII',
                                              'UTF8', 'UTF-8'):
                    encoding = '0'
                else:
                    encoding = '"%s"' % py_string.encoding.lower()

Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
1246
                decls_writer.putln(
1247
                    "static PyObject *%s;" % py_string.cname)
1248 1249 1250 1251 1252 1253 1254
                if py_string.py3str_cstring:
                    w.putln("#if PY_MAJOR_VERSION >= 3")
                    w.putln(
                        "{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % (
                        py_string.cname,
                        py_string.py3str_cstring.cname,
                        py_string.py3str_cstring.cname,
1255 1256
                        '0', 1, 0,
                        py_string.intern
1257 1258
                        ))
                    w.putln("#else")
1259
                w.putln(
1260
                    "{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % (
1261 1262 1263
                    py_string.cname,
                    c_cname,
                    c_cname,
1264 1265 1266 1267
                    encoding,
                    py_string.is_unicode,
                    py_string.is_str,
                    py_string.intern
1268
                    ))
1269 1270
                if py_string.py3str_cstring:
                    w.putln("#endif")
1271
            w.putln("{0, 0, 0, 0, 0, 0, 0}")
1272
            w.putln("};")
1273

1274 1275
            init_globals = self.parts['init_globals']
            init_globals.putln(
1276 1277
                "if (__Pyx_InitStrings(%s) < 0) %s;" % (
                    Naming.stringtab_cname,
1278
                    init_globals.error_goto(self.module_pos)))
1279

Stefan Behnel's avatar
Stefan Behnel committed
1280
    def generate_num_constants(self):
1281
        consts = [(c.py_type, c.value[0] == '-', len(c.value), c.value, c.value_code, c)
Stefan Behnel's avatar
Stefan Behnel committed
1282
                  for c in self.num_const_index.values()]
1283
        consts.sort()
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
1284
        decls_writer = self.parts['decls']
Stefan Behnel's avatar
Stefan Behnel committed
1285
        init_globals = self.parts['init_globals']
1286
        for py_type, _, _, value, value_code, c in consts:
1287
            cname = c.cname
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
1288
            decls_writer.putln("static PyObject *%s;" % cname)
Stefan Behnel's avatar
Stefan Behnel committed
1289
            if py_type == 'float':
Stefan Behnel's avatar
Stefan Behnel committed
1290
                function = 'PyFloat_FromDouble(%s)'
Stefan Behnel's avatar
Stefan Behnel committed
1291
            elif py_type == 'long':
Stefan Behnel's avatar
Stefan Behnel committed
1292
                function = 'PyLong_FromString((char *)"%s", 0, 0)'
1293
            elif Utils.long_literal(value):
Stefan Behnel's avatar
Stefan Behnel committed
1294
                function = 'PyInt_FromString((char *)"%s", 0, 0)'
1295 1296
            elif len(value.lstrip('-')) > 4:
                function = "PyInt_FromLong(%sL)"
1297
            else:
Stefan Behnel's avatar
Stefan Behnel committed
1298 1299 1300
                function = "PyInt_FromLong(%s)"
            init_globals.putln('%s = %s; %s' % (
                cname, function % value_code,
1301
                init_globals.error_goto_if_null(cname, self.module_pos)))
1302

1303 1304 1305
    # The functions below are there in a transition phase only
    # and will be deprecated. They are called from Nodes.BlockNode.
    # The copy&paste duplication is intentional in order to be able
Robert Bradshaw's avatar
Robert Bradshaw committed
1306
    # to see quickly how BlockNode worked, until this is replaced.
1307

1308 1309 1310
    def should_declare(self, cname, entry):
        if cname in self.declared_cnames:
            other = self.declared_cnames[cname]
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
1311
            assert str(entry.type) == str(other.type)
1312 1313 1314 1315 1316 1317 1318 1319 1320
            assert entry.init == other.init
            return False
        else:
            self.declared_cnames[cname] = entry
            return True

    #
    # File name state
    #
1321

1322
    def lookup_filename(self, source_desc):
1323
        try:
1324
            index = self.filename_table[source_desc.get_filenametable_entry()]
1325 1326
        except KeyError:
            index = len(self.filename_list)
1327 1328
            self.filename_list.append(source_desc)
            self.filename_table[source_desc.get_filenametable_entry()] = index
1329 1330 1331 1332 1333 1334
        return index

    def commented_file_contents(self, source_desc):
        try:
            return self.input_file_contents[source_desc]
        except KeyError:
1335 1336 1337 1338
            pass
        source_file = source_desc.get_lines(encoding='ASCII',
                                            error_handling='ignore')
        try:
1339 1340
            F = [u' * ' + line.rstrip().replace(
                    u'*/', u'*[inserted by cython to avoid comment closer]/'
1341 1342
                    ).replace(
                    u'/*', u'/[inserted by cython to avoid comment start]*'
1343
                    )
1344 1345 1346 1347 1348 1349 1350
                 for line in source_file]
        finally:
            if hasattr(source_file, 'close'):
                source_file.close()
        if not F: F.append(u'')
        self.input_file_contents[source_desc] = F
        return F
1351

1352 1353 1354
    #
    # Utility code state
    #
Robert Bradshaw's avatar
Robert Bradshaw committed
1355

1356
    def use_utility_code(self, utility_code):
1357
        """
1358 1359 1360 1361
        Adds code to the C file. utility_code should
        a) implement __eq__/__hash__ for the purpose of knowing whether the same
           code has already been included
        b) implement put_code, which takes a globalstate instance
1362

1363
        See UtilityCode.
1364
        """
1365 1366 1367
        if utility_code not in self.utility_codes:
            self.utility_codes.add(utility_code)
            utility_code.put_code(self)
1368

1369

1370
def funccontext_property(name):
1371
    attribute_of = operator.attrgetter(name)
1372
    def get(self):
1373
        return attribute_of(self.funcstate)
1374
    def set(self, value):
1375
        setattr(self.funcstate, name, value)
1376 1377
    return property(get, set)

1378

1379
class CCodeWriter(object):
1380
    """
1381
    Utility class to output C code.
1382

1383
    When creating an insertion point one must care about the state that is
1384
    kept:
1385 1386
    - formatting state (level, bol) is cloned and used in insertion points
      as well
1387 1388
    - labels, temps, exc_vars: One must construct a scope in which these can
      exist by calling enter_cfunc_scope/exit_cfunc_scope (these are for
1389 1390 1391 1392 1393
      sanity checking and forward compatabilty). Created insertion points
      looses this scope and cannot access it.
    - marker: Not copied to insertion point
    - filename_table, filename_list, input_file_contents: All codewriters
      coming from the same root share the same instances simultaneously.
1394
    """
Robert Bradshaw's avatar
Robert Bradshaw committed
1395

1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406
    # f                   file            output file
    # buffer              StringIOTree

    # level               int             indentation level
    # bol                 bool            beginning of line?
    # marker              string          comment to emit before next line
    # funcstate           FunctionState   contains state local to a C function used for code
    #                                     generation (labels and temps state etc.)
    # globalstate         GlobalState     contains state global for a C file (input file info,
    #                                     utility code, declared constants etc.)
    # emit_linenums       boolean         whether or not to write #line pragmas
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
1407
    #
1408 1409 1410 1411
    # c_line_in_traceback boolean         append the c file and line number to the traceback for exceptions
    #
    # pyclass_stack       list            used during recursive code generation to pass information
    #                                     about the current class one is in
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
1412

1413
    globalstate = None
Robert Bradshaw's avatar
Robert Bradshaw committed
1414

1415
    def __init__(self, create_from=None, buffer=None, copy_formatting=False, emit_linenums=None, c_line_in_traceback=True):
1416 1417
        if buffer is None: buffer = StringIOTree()
        self.buffer = buffer
1418 1419
        self.last_pos = None
        self.last_marked_pos = None
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
1420
        self.pyclass_stack = []
Robert Bradshaw's avatar
Robert Bradshaw committed
1421

1422 1423
        self.funcstate = None
        self.level = 0
Robert Bradshaw's avatar
Robert Bradshaw committed
1424
        self.call_level = 0
1425
        self.bol = 1
1426 1427

        if create_from is not None:
1428 1429
            # Use same global state
            self.globalstate = create_from.globalstate
1430
            self.funcstate = create_from.funcstate
1431
            # Clone formatting state
1432 1433 1434
            if copy_formatting:
                self.level = create_from.level
                self.bol = create_from.bol
Robert Bradshaw's avatar
Robert Bradshaw committed
1435
                self.call_level = create_from.call_level
1436 1437
            self.last_pos = create_from.last_pos
            self.last_marked_pos = create_from.last_marked_pos
1438

1439
        if emit_linenums is None and self.globalstate:
1440 1441 1442
            self.emit_linenums = self.globalstate.emit_linenums
        else:
            self.emit_linenums = emit_linenums
1443
        self.c_line_in_traceback = c_line_in_traceback
1444

1445
    def create_new(self, create_from, buffer, copy_formatting):
1446 1447
        # polymorphic constructor -- very slightly more versatile
        # than using __class__
1448 1449
        result = CCodeWriter(create_from, buffer, copy_formatting,
                             c_line_in_traceback=self.c_line_in_traceback)
1450
        return result
1451 1452 1453 1454

    def copyto(self, f):
        self.buffer.copyto(f)

1455 1456 1457 1458
    def getvalue(self):
        return self.buffer.getvalue()

    def write(self, s):
Robert Bradshaw's avatar
Robert Bradshaw committed
1459
        # also put invalid markers (lineno 0), to indicate that those lines
Mark Florisson's avatar
Mark Florisson committed
1460
        # have no Cython source code correspondence
1461
        cython_lineno = self.last_marked_pos[1] if self.last_marked_pos else 0
Mark Florisson's avatar
Mark Florisson committed
1462
        self.buffer.markers.extend([cython_lineno] * s.count('\n'))
1463
        self.buffer.write(s)
1464 1465

    def insertion_point(self):
1466
        other = self.create_new(create_from=self, buffer=self.buffer.insertion_point(), copy_formatting=True)
1467 1468
        return other

1469 1470 1471 1472 1473
    def new_writer(self):
        """
        Creates a new CCodeWriter connected to the same global state, which
        can later be inserted using insert.
        """
1474
        return CCodeWriter(create_from=self, c_line_in_traceback=self.c_line_in_traceback)
1475 1476 1477 1478 1479 1480 1481 1482 1483 1484

    def insert(self, writer):
        """
        Inserts the contents of another code writer (created with
        the same global state) in the current location.

        It is ok to write to the inserted writer also after insertion.
        """
        assert writer.globalstate is self.globalstate
        self.buffer.insert(writer.buffer)
1485 1486 1487 1488 1489 1490 1491 1492

    # Properties delegated to function scope
    label_counter = funccontext_property("label_counter")
    return_label = funccontext_property("return_label")
    error_label = funccontext_property("error_label")
    labels_used = funccontext_property("labels_used")
    continue_label = funccontext_property("continue_label")
    break_label = funccontext_property("break_label")
1493
    return_from_error_cleanup_label = funccontext_property("return_from_error_cleanup_label")
1494
    yield_labels = funccontext_property("yield_labels")
1495 1496

    # Functions delegated to function scope
Dag Sverre Seljebotn's avatar
merge  
Dag Sverre Seljebotn committed
1497
    def new_label(self, name=None):    return self.funcstate.new_label(name)
1498
    def new_error_label(self):         return self.funcstate.new_error_label()
1499
    def new_yield_label(self):         return self.funcstate.new_yield_label()
1500 1501 1502 1503 1504 1505 1506 1507
    def get_loop_labels(self):         return self.funcstate.get_loop_labels()
    def set_loop_labels(self, labels): return self.funcstate.set_loop_labels(labels)
    def new_loop_labels(self):         return self.funcstate.new_loop_labels()
    def get_all_labels(self):          return self.funcstate.get_all_labels()
    def set_all_labels(self, labels):  return self.funcstate.set_all_labels(labels)
    def all_new_labels(self):          return self.funcstate.all_new_labels()
    def use_label(self, lbl):          return self.funcstate.use_label(lbl)
    def label_used(self, lbl):         return self.funcstate.label_used(lbl)
1508 1509


1510
    def enter_cfunc_scope(self):
1511
        self.funcstate = FunctionState(self)
Robert Bradshaw's avatar
Robert Bradshaw committed
1512

1513
    def exit_cfunc_scope(self):
1514
        self.funcstate = None
1515

1516 1517
    # constant handling

Stefan Behnel's avatar
Stefan Behnel committed
1518
    def get_py_int(self, str_value, longness):
1519 1520
        return self.globalstate.get_int_const(str_value, longness).cname

Stefan Behnel's avatar
Stefan Behnel committed
1521 1522 1523
    def get_py_float(self, str_value, value_code):
        return self.globalstate.get_float_const(str_value, value_code).cname

1524 1525
    def get_py_const(self, type, prefix='', cleanup_level=None):
        return self.globalstate.get_py_const(type, prefix, cleanup_level).cname
1526

1527 1528 1529
    def get_string_const(self, text):
        return self.globalstate.get_string_const(text).cname

1530 1531
    def get_pyunicode_ptr_const(self, text):
        return self.globalstate.get_pyunicode_ptr_const(text)
1532

1533 1534 1535 1536
    def get_py_string_const(self, text, identifier=None,
                            is_str=False, unicode_value=None):
        return self.globalstate.get_py_string_const(
            text, identifier, is_str, unicode_value).cname
1537

1538 1539 1540
    def get_argument_default_const(self, type):
        return self.globalstate.get_py_const(type).cname

1541 1542 1543 1544
    def intern(self, text):
        return self.get_py_string_const(text)

    def intern_identifier(self, text):
1545
        return self.get_py_string_const(text, identifier=True)
1546

1547 1548 1549
    def get_cached_constants_writer(self):
        return self.globalstate.get_cached_constants_writer()

1550 1551
    # code generation

Stefan Behnel's avatar
Stefan Behnel committed
1552
    def putln(self, code="", safe=False):
1553
        if self.last_pos and self.bol:
William Stein's avatar
William Stein committed
1554
            self.emit_marker()
1555 1556 1557
        if self.emit_linenums and self.last_marked_pos:
            source_desc, line, _ = self.last_marked_pos
            self.write('\n#line %s "%s"\n' % (line, source_desc.get_escaped_description()))
William Stein's avatar
William Stein committed
1558
        if code:
1559 1560 1561 1562
            if safe:
                self.put_safe(code)
            else:
                self.put(code)
1563
        self.write("\n")
William Stein's avatar
William Stein committed
1564
        self.bol = 1
Robert Bradshaw's avatar
Robert Bradshaw committed
1565

1566 1567 1568 1569 1570 1571 1572
    def mark_pos(self, pos):
        if pos is None:
            return
        if self.last_marked_pos and self.last_marked_pos[:2] == pos[:2]:
            return
        self.last_pos = pos

William Stein's avatar
William Stein committed
1573
    def emit_marker(self):
1574 1575
        pos = self.last_marked_pos = self.last_pos
        self.last_pos = None
1576
        self.write("\n")
William Stein's avatar
William Stein committed
1577
        self.indent()
1578 1579
        self.write("/* %s */\n" % self._build_marker(pos))
        if self.funcstate and self.funcstate.can_trace and self.globalstate.directives['linetrace']:
1580
            self.indent()
1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591
            self.write('__Pyx_TraceLine(%d,%d,%s)\n' % (
                pos[1], not self.funcstate.gil_owned, self.error_goto(pos)))

    def _build_marker(self, pos):
        source_desc, line, col = pos
        assert isinstance(source_desc, SourceDescriptor)
        contents = self.globalstate.commented_file_contents(source_desc)
        lines = contents[max(0, line-3):line]  # line numbers start at 1
        lines[-1] += u'             # <<<<<<<<<<<<<<'
        lines += contents[line:line+2]
        return u'"%s":%d\n%s\n' % (source_desc.get_escaped_description(), line, u'\n'.join(lines))
William Stein's avatar
William Stein committed
1592

1593 1594 1595 1596 1597
    def put_safe(self, code):
        # put code, but ignore {}
        self.write(code)
        self.bol = 0

1598
    def put_or_include(self, code, name):
Stefan Behnel's avatar
Stefan Behnel committed
1599
        include_dir = self.globalstate.common_utility_include_dir
1600
        if include_dir and len(code) > 1024:
Stefan Behnel's avatar
Stefan Behnel committed
1601
            include_file = "%s_%s.h" % (
1602
                name, hashlib.md5(code.encode('utf8')).hexdigest())
Stefan Behnel's avatar
Stefan Behnel committed
1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613
            path = os.path.join(include_dir, include_file)
            if not os.path.exists(path):
                tmp_path = '%s.tmp%s' % (path, os.getpid())
                f = Utils.open_new_file(tmp_path)
                try:
                    f.write(code)
                finally:
                    f.close()
                os.rename(tmp_path, path)
            code = '#include "%s"\n' % path
        self.put(code)
1614

William Stein's avatar
William Stein committed
1615
    def put(self, code):
1616 1617
        if is_self_assignment(code):
            return
1618
        fix_indent = False
1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630
        if "{" in code:
            dl = code.count("{")
        else:
            dl = 0
        if "}" in code:
            dl -= code.count("}")
            if dl < 0:
                self.level += dl
            elif dl == 0 and code[0] == "}":
                # special cases like "} else {" need a temporary dedent
                fix_indent = True
                self.level -= 1
William Stein's avatar
William Stein committed
1631 1632
        if self.bol:
            self.indent()
1633
        self.write(code)
William Stein's avatar
William Stein committed
1634 1635 1636
        self.bol = 0
        if dl > 0:
            self.level += dl
1637
        elif fix_indent:
1638 1639
            self.level += 1

Mark Florisson's avatar
Mark Florisson committed
1640
    def putln_tempita(self, code, **context):
1641
        from ..Tempita import sub
1642
        self.putln(sub(code, **context))
Mark Florisson's avatar
Mark Florisson committed
1643 1644

    def put_tempita(self, code, **context):
1645
        from ..Tempita import sub
1646
        self.put(sub(code, **context))
Mark Florisson's avatar
Mark Florisson committed
1647

William Stein's avatar
William Stein committed
1648
    def increase_indent(self):
Stefan Behnel's avatar
Stefan Behnel committed
1649
        self.level += 1
Robert Bradshaw's avatar
Robert Bradshaw committed
1650

William Stein's avatar
William Stein committed
1651
    def decrease_indent(self):
Stefan Behnel's avatar
Stefan Behnel committed
1652
        self.level -= 1
Robert Bradshaw's avatar
Robert Bradshaw committed
1653

William Stein's avatar
William Stein committed
1654 1655 1656
    def begin_block(self):
        self.putln("{")
        self.increase_indent()
Robert Bradshaw's avatar
Robert Bradshaw committed
1657

William Stein's avatar
William Stein committed
1658 1659 1660
    def end_block(self):
        self.decrease_indent()
        self.putln("}")
Robert Bradshaw's avatar
Robert Bradshaw committed
1661

William Stein's avatar
William Stein committed
1662
    def indent(self):
1663
        self.write("  " * self.level)
1664

1665 1666 1667
    def get_py_version_hex(self, pyversion):
        return "0x%02X%02X%02X%02X" % (tuple(pyversion) + (0,0,0,0))[:4]

William Stein's avatar
William Stein committed
1668
    def put_label(self, lbl):
1669
        if lbl in self.funcstate.labels_used:
1670
            self.putln("%s:;" % lbl)
Robert Bradshaw's avatar
Robert Bradshaw committed
1671

1672
    def put_goto(self, lbl):
1673
        self.funcstate.use_label(lbl)
1674
        self.putln("goto %s;" % lbl)
Robert Bradshaw's avatar
Robert Bradshaw committed
1675

1676
    def put_var_declaration(self, entry, storage_class="",
Stefan Behnel's avatar
Stefan Behnel committed
1677
                            dll_linkage=None, definition=True):
1678
        #print "Code.put_var_declaration:", entry.name, "definition =", definition ###
1679 1680
        if entry.visibility == 'private' and not (definition or entry.defined_in_pxd):
            #print "...private and not definition, skipping", entry.cname ###
1681
            return
1682 1683
        if entry.visibility == "private" and not entry.used:
            #print "...private and not used, skipping", entry.cname ###
William Stein's avatar
William Stein committed
1684 1685 1686
            return
        if storage_class:
            self.put("%s " % storage_class)
1687 1688
        if not entry.cf_used:
            self.put('CYTHON_UNUSED ')
1689
        self.put(entry.type.declaration_code(
Stefan Behnel's avatar
Stefan Behnel committed
1690
            entry.cname, dll_linkage=dll_linkage))
William Stein's avatar
William Stein committed
1691
        if entry.init is not None:
1692
            self.put_safe(" = %s" % entry.type.literal_code(entry.init))
1693
        elif entry.type.is_pyobject:
Stefan Behnel's avatar
Stefan Behnel committed
1694
            self.put(" = NULL")
William Stein's avatar
William Stein committed
1695
        self.putln(";")
1696 1697

    def put_temp_declarations(self, func_context):
1698
        for name, type, manage_ref, static in func_context.temps_allocated:
1699 1700 1701
            decl = type.declaration_code(name)
            if type.is_pyobject:
                self.putln("%s = NULL;" % decl)
1702
            elif type.is_memoryviewslice:
1703
                from . import MemoryView
Mark Florisson's avatar
Mark Florisson committed
1704
                self.putln("%s = %s;" % (decl, MemoryView.memslice_entry_init))
1705
            else:
1706
                self.putln("%s%s;" % (static and "static " or "", decl))
1707

1708
        if func_context.should_declare_error_indicator:
1709 1710 1711 1712
            if self.funcstate.uses_error_indicator:
                unused = ''
            else:
                unused = 'CYTHON_UNUSED '
1713
            # Initialize these variables to silence compiler warnings
1714 1715 1716
            self.putln("%sint %s = 0;" % (unused, Naming.lineno_cname))
            self.putln("%sconst char *%s = NULL;" % (unused, Naming.filename_cname))
            self.putln("%sint %s = 0;" % (unused, Naming.clineno_cname))
1717

1718 1719 1720
    def put_h_guard(self, guard):
        self.putln("#ifndef %s" % guard)
        self.putln("#define %s" % guard)
Robert Bradshaw's avatar
Robert Bradshaw committed
1721

1722 1723 1724 1725 1726 1727
    def unlikely(self, cond):
        if Options.gcc_branch_hints:
            return 'unlikely(%s)' % cond
        else:
            return cond

1728 1729 1730 1731 1732
    def build_function_modifiers(self, modifiers, mapper=modifier_output_mapper):
        if not modifiers:
            return ''
        return '%s ' % ' '.join([mapper(m,m) for m in modifiers])

1733 1734
    # Python objects and reference counting

William Stein's avatar
William Stein committed
1735 1736
    def entry_as_pyobject(self, entry):
        type = entry.type
1737 1738
        if (not entry.is_self_arg and not entry.type.is_complete()
            or entry.type.is_extension_type):
William Stein's avatar
William Stein committed
1739 1740 1741
            return "(PyObject *)" + entry.cname
        else:
            return entry.cname
Robert Bradshaw's avatar
Robert Bradshaw committed
1742

William Stein's avatar
William Stein committed
1743
    def as_pyobject(self, cname, type):
1744
        from .PyrexTypes import py_object_type, typecast
William Stein's avatar
William Stein committed
1745
        return typecast(py_object_type, type, cname)
Robert Bradshaw's avatar
Robert Bradshaw committed
1746

1747
    def put_gotref(self, cname):
1748
        self.putln("__Pyx_GOTREF(%s);" % cname)
Robert Bradshaw's avatar
Robert Bradshaw committed
1749

1750 1751
    def put_giveref(self, cname):
        self.putln("__Pyx_GIVEREF(%s);" % cname)
Robert Bradshaw's avatar
Robert Bradshaw committed
1752

1753 1754 1755
    def put_xgiveref(self, cname):
        self.putln("__Pyx_XGIVEREF(%s);" % cname)

Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
1756 1757 1758
    def put_xgotref(self, cname):
        self.putln("__Pyx_XGOTREF(%s);" % cname)

1759 1760 1761 1762 1763
    def put_incref(self, cname, type, nanny=True):
        if nanny:
            self.putln("__Pyx_INCREF(%s);" % self.as_pyobject(cname, type))
        else:
            self.putln("Py_INCREF(%s);" % self.as_pyobject(cname, type))
Robert Bradshaw's avatar
Robert Bradshaw committed
1764

1765
    def put_decref(self, cname, type, nanny=True):
1766
        self._put_decref(cname, type, nanny, null_check=False, clear=False)
1767 1768 1769 1770

    def put_var_gotref(self, entry):
        if entry.type.is_pyobject:
            self.putln("__Pyx_GOTREF(%s);" % self.entry_as_pyobject(entry))
Robert Bradshaw's avatar
Robert Bradshaw committed
1771

1772 1773 1774 1775
    def put_var_giveref(self, entry):
        if entry.type.is_pyobject:
            self.putln("__Pyx_GIVEREF(%s);" % self.entry_as_pyobject(entry))

1776 1777 1778 1779
    def put_var_xgotref(self, entry):
        if entry.type.is_pyobject:
            self.putln("__Pyx_XGOTREF(%s);" % self.entry_as_pyobject(entry))

1780 1781 1782 1783
    def put_var_xgiveref(self, entry):
        if entry.type.is_pyobject:
            self.putln("__Pyx_XGIVEREF(%s);" % self.entry_as_pyobject(entry))

William Stein's avatar
William Stein committed
1784 1785
    def put_var_incref(self, entry):
        if entry.type.is_pyobject:
1786
            self.putln("__Pyx_INCREF(%s);" % self.entry_as_pyobject(entry))
Robert Bradshaw's avatar
Robert Bradshaw committed
1787

1788 1789 1790
    def put_decref_clear(self, cname, type, nanny=True, clear_before_decref=False):
        self._put_decref(cname, type, nanny, null_check=False,
                         clear=True, clear_before_decref=clear_before_decref)
Robert Bradshaw's avatar
Robert Bradshaw committed
1791

1792
    def put_xdecref(self, cname, type, nanny=True, have_gil=True):
1793 1794
        self._put_decref(cname, type, nanny, null_check=True,
                         have_gil=have_gil, clear=False)
1795

1796 1797 1798
    def put_xdecref_clear(self, cname, type, nanny=True, clear_before_decref=False):
        self._put_decref(cname, type, nanny, null_check=True,
                         clear=True, clear_before_decref=clear_before_decref)
Robert Bradshaw's avatar
Robert Bradshaw committed
1799

1800 1801
    def _put_decref(self, cname, type, nanny=True, null_check=False,
                    have_gil=True, clear=False, clear_before_decref=False):
1802
        if type.is_memoryviewslice:
1803
            self.put_xdecref_memoryviewslice(cname, have_gil=have_gil)
1804 1805
            return

1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816
        prefix = nanny and '__Pyx' or 'Py'
        X = null_check and 'X' or ''

        if clear:
            if clear_before_decref:
                if not nanny:
                    X = ''  # CPython doesn't have a Py_XCLEAR()
                self.putln("%s_%sCLEAR(%s);" % (prefix, X, cname))
            else:
                self.putln("%s_%sDECREF(%s); %s = 0;" % (
                    prefix, X, self.as_pyobject(cname, type), cname))
1817
        else:
1818 1819
            self.putln("%s_%sDECREF(%s);" % (
                prefix, X, self.as_pyobject(cname, type)))
William Stein's avatar
William Stein committed
1820

1821 1822 1823 1824 1825 1826
    def put_decref_set(self, cname, rhs_cname):
        self.putln("__Pyx_DECREF_SET(%s, %s);" % (cname, rhs_cname))

    def put_xdecref_set(self, cname, rhs_cname):
        self.putln("__Pyx_XDECREF_SET(%s, %s);" % (cname, rhs_cname))

William Stein's avatar
William Stein committed
1827 1828
    def put_var_decref(self, entry):
        if entry.type.is_pyobject:
1829
            self.putln("__Pyx_XDECREF(%s);" % self.entry_as_pyobject(entry))
Robert Bradshaw's avatar
Robert Bradshaw committed
1830

William Stein's avatar
William Stein committed
1831 1832
    def put_var_xdecref(self, entry):
        if entry.type.is_pyobject:
1833
            self.putln("__Pyx_XDECREF(%s);" % self.entry_as_pyobject(entry))
Robert Bradshaw's avatar
Robert Bradshaw committed
1834

1835 1836 1837
    def put_var_decref_clear(self, entry):
        self._put_var_decref_clear(entry, null_check=False)

William Stein's avatar
William Stein committed
1838
    def put_var_xdecref_clear(self, entry):
1839 1840 1841
        self._put_var_decref_clear(entry, null_check=True)

    def _put_var_decref_clear(self, entry, null_check):
William Stein's avatar
William Stein committed
1842
        if entry.type.is_pyobject:
1843 1844 1845 1846 1847 1848 1849 1850 1851
            if entry.in_closure:
                # reset before DECREF to make sure closure state is
                # consistent during call to DECREF()
                self.putln("__Pyx_%sCLEAR(%s);" % (
                    null_check and 'X' or '',
                    entry.cname))
            else:
                self.putln("__Pyx_%sDECREF(%s); %s = 0;" % (
                    null_check and 'X' or '',
1852
                    self.entry_as_pyobject(entry),
1853
                    entry.cname))
Robert Bradshaw's avatar
Robert Bradshaw committed
1854

1855
    def put_var_decrefs(self, entries, used_only = 0):
William Stein's avatar
William Stein committed
1856
        for entry in entries:
1857 1858 1859 1860 1861
            if not used_only or entry.used:
                if entry.xdecref_cleanup:
                    self.put_var_xdecref(entry)
                else:
                    self.put_var_decref(entry)
Robert Bradshaw's avatar
Robert Bradshaw committed
1862

William Stein's avatar
William Stein committed
1863 1864 1865
    def put_var_xdecrefs(self, entries):
        for entry in entries:
            self.put_var_xdecref(entry)
Robert Bradshaw's avatar
Robert Bradshaw committed
1866

William Stein's avatar
William Stein committed
1867 1868 1869
    def put_var_xdecrefs_clear(self, entries):
        for entry in entries:
            self.put_var_xdecref_clear(entry)
Robert Bradshaw's avatar
Robert Bradshaw committed
1870

1871
    def put_incref_memoryviewslice(self, slice_cname, have_gil=False):
1872
        from . import MemoryView
Mark Florisson's avatar
Mark Florisson committed
1873
        self.globalstate.use_utility_code(MemoryView.memviewslice_init_code)
1874 1875 1876
        self.putln("__PYX_INC_MEMVIEW(&%s, %d);" % (slice_cname, int(have_gil)))

    def put_xdecref_memoryviewslice(self, slice_cname, have_gil=False):
1877
        from . import MemoryView
Mark Florisson's avatar
Mark Florisson committed
1878
        self.globalstate.use_utility_code(MemoryView.memviewslice_init_code)
1879 1880 1881 1882 1883
        self.putln("__PYX_XDEC_MEMVIEW(&%s, %d);" % (slice_cname, int(have_gil)))

    def put_xgiveref_memoryviewslice(self, slice_cname):
        self.put_xgiveref("%s.memview" % slice_cname)

1884
    def put_init_to_py_none(self, cname, type, nanny=True):
1885
        from .PyrexTypes import py_object_type, typecast
William Stein's avatar
William Stein committed
1886
        py_none = typecast(type, py_object_type, "Py_None")
1887 1888 1889 1890
        if nanny:
            self.putln("%s = %s; __Pyx_INCREF(Py_None);" % (cname, py_none))
        else:
            self.putln("%s = %s; Py_INCREF(Py_None);" % (cname, py_none))
Robert Bradshaw's avatar
Robert Bradshaw committed
1891

1892
    def put_init_var_to_py_none(self, entry, template = "%s", nanny=True):
William Stein's avatar
William Stein committed
1893 1894
        code = template % entry.cname
        #if entry.type.is_extension_type:
Robert Bradshaw's avatar
Robert Bradshaw committed
1895
        #    code = "((PyObject*)%s)" % code
1896
        self.put_init_to_py_none(code, entry.type, nanny)
1897
        if entry.in_closure:
Stefan Behnel's avatar
Stefan Behnel committed
1898
            self.put_giveref('Py_None')
William Stein's avatar
William Stein committed
1899

1900
    def put_pymethoddef(self, entry, term, allow_skip=True):
1901
        if entry.is_special or entry.name == '__getattribute__':
1902 1903 1904
            if entry.name not in ['__cinit__', '__dealloc__', '__richcmp__', '__next__', '__getreadbuffer__', '__getwritebuffer__', '__getsegcount__', '__getcharbuffer__', '__getbuffer__', '__releasebuffer__']:
                if entry.name == '__getattr__' and not self.globalstate.directives['fast_getattr']:
                    pass
1905 1906 1907
                # Python's typeobject.c will automatically fill in our slot
                # in add_operators() (called by PyType_Ready) with a value
                # that's better than ours.
1908
                elif allow_skip:
1909
                    return
1910
        from .TypeSlots import method_coexist
William Stein's avatar
William Stein committed
1911 1912 1913 1914
        if entry.doc:
            doc_code = entry.doc_cname
        else:
            doc_code = 0
1915 1916
        method_flags = entry.signature.method_flags()
        if method_flags:
1917
            if entry.is_special:
1918
                method_flags += [method_coexist]
1919
            self.putln(
1920
                '{"%s", (PyCFunction)%s, %s, %s}%s' % (
Robert Bradshaw's avatar
Robert Bradshaw committed
1921
                    entry.name,
1922
                    entry.func_cname,
1923
                    "|".join(method_flags),
1924 1925
                    doc_code,
                    term))
1926

1927 1928
    # GIL methods

1929
    def put_ensure_gil(self, declare_gilstate=True, variable=None):
1930 1931 1932 1933 1934 1935
        """
        Acquire the GIL. The generated code is safe even when no PyThreadState
        has been allocated for this thread (for threads not initialized by
        using the Python API). Additionally, the code generated by this method
        may be called recursively.
        """
1936 1937
        self.globalstate.use_utility_code(
            UtilityCode.load_cached("ForceInitThreads", "ModuleSetupCode.c"))
1938
        self.putln("#ifdef WITH_THREAD")
1939 1940 1941 1942 1943
        if not variable:
            variable = '__pyx_gilstate_save'
            if declare_gilstate:
                self.put("PyGILState_STATE ")
        self.putln("%s = PyGILState_Ensure();" % variable)
1944 1945
        self.putln("#endif")

1946
    def put_release_ensured_gil(self, variable=None):
1947 1948 1949
        """
        Releases the GIL, corresponds to `put_ensure_gil`.
        """
1950 1951
        if not variable:
            variable = '__pyx_gilstate_save'
1952
        self.putln("#ifdef WITH_THREAD")
1953
        self.putln("PyGILState_Release(%s);" % variable)
1954 1955
        self.putln("#endif")

1956
    def put_acquire_gil(self, variable=None):
1957 1958 1959 1960
        """
        Acquire the GIL. The thread's thread state must have been initialized
        by a previous `put_release_gil`
        """
1961 1962 1963
        self.putln("#ifdef WITH_THREAD")
        if variable:
            self.putln('_save = %s;' % variable)
1964
        self.putln("Py_BLOCK_THREADS")
1965
        self.putln("#endif")
1966

1967
    def put_release_gil(self, variable=None):
1968 1969
        "Release the GIL, corresponds to `put_acquire_gil`."
        self.putln("#ifdef WITH_THREAD")
1970
        self.putln("PyThreadState *_save;")
1971
        self.putln("Py_UNBLOCK_THREADS")
1972 1973 1974
        if variable:
            self.putln('%s = _save;' % variable)
        self.putln("#endif")
1975

1976 1977
    def declare_gilstate(self):
        self.putln("#ifdef WITH_THREAD")
1978
        self.putln("PyGILState_STATE __pyx_gilstate_save;")
1979 1980
        self.putln("#endif")

1981 1982
    # error handling

Robert Bradshaw's avatar
Robert Bradshaw committed
1983 1984 1985 1986
    def put_error_if_neg(self, pos, value):
#        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!
        return self.putln("if (%s < 0) %s" % (value, self.error_goto(pos)))

1987
    def put_error_if_unbound(self, pos, entry, in_nogil_context=False):
1988
        from . import ExprNodes
1989
        if entry.from_closure:
1990 1991 1992
            func = '__Pyx_RaiseClosureNameError'
            self.globalstate.use_utility_code(
                ExprNodes.raise_closure_name_error_utility_code)
1993 1994 1995 1996
        elif entry.type.is_memoryviewslice and in_nogil_context:
            func = '__Pyx_RaiseUnboundMemoryviewSliceNogil'
            self.globalstate.use_utility_code(
                ExprNodes.raise_unbound_memoryview_utility_code_nogil)
1997
        else:
1998 1999 2000
            func = '__Pyx_RaiseUnboundLocalError'
            self.globalstate.use_utility_code(
                ExprNodes.raise_unbound_local_error_utility_code)
Mark Florisson's avatar
Mark Florisson committed
2001

2002
        self.putln('if (unlikely(!%s)) { %s("%s"); %s }' % (
Mark Florisson's avatar
Mark Florisson committed
2003 2004 2005 2006
                                entry.type.check_for_null_code(entry.cname),
                                func,
                                entry.name,
                                self.error_goto(pos)))
2007

2008
    def set_error_info(self, pos, used=False):
2009
        self.funcstate.should_declare_error_indicator = True
2010 2011
        if used:
            self.funcstate.uses_error_indicator = True
2012
        if self.c_line_in_traceback:
2013
            cinfo = " %s = %s;" % (Naming.clineno_cname, Naming.line_c_macro)
Robert Bradshaw's avatar
Robert Bradshaw committed
2014 2015
        else:
            cinfo = ""
2016

2017
        return "%s = %s[%s]; %s = %s;%s" % (
William Stein's avatar
William Stein committed
2018 2019 2020 2021 2022
            Naming.filename_cname,
            Naming.filetable_cname,
            self.lookup_filename(pos[0]),
            Naming.lineno_cname,
            pos[1],
2023
            cinfo)
Robert Bradshaw's avatar
Robert Bradshaw committed
2024

2025 2026 2027 2028 2029
    def error_goto(self, pos):
        lbl = self.funcstate.error_label
        self.funcstate.use_label(lbl)
        return "{%s goto %s;}" % (
            self.set_error_info(pos),
2030
            lbl)
2031 2032 2033

    def error_goto_if(self, cond, pos):
        return "if (%s) %s" % (self.unlikely(cond), self.error_goto(pos))
Robert Bradshaw's avatar
Robert Bradshaw committed
2034

Robert Bradshaw's avatar
Robert Bradshaw committed
2035 2036
    def error_goto_if_null(self, cname, pos):
        return self.error_goto_if("!%s" % cname, pos)
Robert Bradshaw's avatar
Robert Bradshaw committed
2037

Robert Bradshaw's avatar
Robert Bradshaw committed
2038 2039
    def error_goto_if_neg(self, cname, pos):
        return self.error_goto_if("%s < 0" % cname, pos)
Robert Bradshaw's avatar
Robert Bradshaw committed
2040

Robert Bradshaw's avatar
Robert Bradshaw committed
2041 2042
    def error_goto_if_PyErr(self, pos):
        return self.error_goto_if("PyErr_Occurred()", pos)
Robert Bradshaw's avatar
Robert Bradshaw committed
2043

William Stein's avatar
William Stein committed
2044
    def lookup_filename(self, filename):
2045
        return self.globalstate.lookup_filename(filename)
William Stein's avatar
William Stein committed
2046

2047
    def put_declare_refcount_context(self):
2048
        self.putln('__Pyx_RefNannyDeclarations')
2049

2050 2051
    def put_setup_refcount_context(self, name, acquire_gil=False):
        if acquire_gil:
2052 2053
            self.globalstate.use_utility_code(
                UtilityCode.load_cached("ForceInitThreads", "ModuleSetupCode.c"))
2054
        self.putln('__Pyx_RefNannySetupContext("%s", %d);' % (name, acquire_gil and 1 or 0))
2055

2056
    def put_finish_refcount_context(self):
2057
        self.putln("__Pyx_RefNannyFinishContext();")
2058

2059 2060 2061 2062
    def put_add_traceback(self, qualified_name):
        """
        Build a Python traceback for propagating exceptions.

2063
        qualified_name should be the qualified name of the function.
2064 2065 2066 2067 2068 2069 2070
        """
        format_tuple = (
            qualified_name,
            Naming.clineno_cname,
            Naming.lineno_cname,
            Naming.filename_cname,
        )
2071
        self.funcstate.uses_error_indicator = True
2072 2073
        self.putln('__Pyx_AddTraceback("%s", %s, %s, %s);' % format_tuple)

2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084
    def put_unraisable(self, qualified_name):
        """
        Generate code to print a Python warning for an unraisable exception.

        qualified_name should be the qualified name of the function.
        """
        format_tuple = (
            qualified_name,
            Naming.clineno_cname,
            Naming.lineno_cname,
            Naming.filename_cname,
2085
            int(self.globalstate.directives['unraisable_tracebacks'])
2086 2087
        )
        self.funcstate.uses_error_indicator = True
2088
        self.putln('__Pyx_WriteUnraisable("%s", %s, %s, %s, %s);' % format_tuple)
2089 2090 2091
        self.globalstate.use_utility_code(
            UtilityCode.load_cached("WriteUnraisableException", "Exceptions.c"))

2092 2093
    def put_trace_declarations(self, codeobj=None, nogil=False):
        self.putln('__Pyx_TraceDeclarations(%s, %d)' % (codeobj or 'NULL', nogil))
Robert Bradshaw's avatar
Robert Bradshaw committed
2094

2095
    def put_trace_call(self, name, pos, nogil=False):
2096 2097
        self.putln('__Pyx_TraceCall("%s", %s[%s], %s, %d, %s);' % (
            name, Naming.filetable_cname, self.lookup_filename(pos[0]), pos[1], nogil, self.error_goto(pos)))
Robert Bradshaw's avatar
Robert Bradshaw committed
2098

Robert Bradshaw's avatar
Robert Bradshaw committed
2099 2100
    def put_trace_exception(self):
        self.putln("__Pyx_TraceException();")
Robert Bradshaw's avatar
Robert Bradshaw committed
2101

2102 2103
    def put_trace_return(self, retvalue_cname, nogil=False):
        self.putln("__Pyx_TraceReturn(%s, %d);" % (retvalue_cname, nogil))
Robert Bradshaw's avatar
Robert Bradshaw committed
2104

Mark Florisson's avatar
Mark Florisson committed
2105 2106 2107
    def putln_openmp(self, string):
        self.putln("#ifdef _OPENMP")
        self.putln(string)
2108
        self.putln("#endif /* _OPENMP */")
William Stein's avatar
William Stein committed
2109

2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129
    def undef_builtin_expect(self, cond):
        """
        Redefine the macros likely() and unlikely to no-ops, depending on
        condition 'cond'
        """
        self.putln("#if %s" % cond)
        self.putln("    #undef likely")
        self.putln("    #undef unlikely")
        self.putln("    #define likely(x)   (x)")
        self.putln("    #define unlikely(x) (x)")
        self.putln("#endif")

    def redef_builtin_expect(self, cond):
        self.putln("#if %s" % cond)
        self.putln("    #undef likely")
        self.putln("    #undef unlikely")
        self.putln("    #define likely(x)   __builtin_expect(!!(x), 1)")
        self.putln("    #define unlikely(x) __builtin_expect(!!(x), 0)")
        self.putln("#endif")

2130
class PyrexCodeWriter(object):
William Stein's avatar
William Stein committed
2131 2132 2133 2134
    # f                file      output file
    # level            int       indentation level

    def __init__(self, outfile_name):
2135
        self.f = Utils.open_new_file(outfile_name)
William Stein's avatar
William Stein committed
2136
        self.level = 0
Robert Bradshaw's avatar
Robert Bradshaw committed
2137

William Stein's avatar
William Stein committed
2138 2139
    def putln(self, code):
        self.f.write("%s%s\n" % (" " * self.level, code))
Robert Bradshaw's avatar
Robert Bradshaw committed
2140

William Stein's avatar
William Stein committed
2141 2142
    def indent(self):
        self.level += 1
Robert Bradshaw's avatar
Robert Bradshaw committed
2143

William Stein's avatar
William Stein committed
2144 2145 2146
    def dedent(self):
        self.level -= 1

2147 2148
class PyxCodeWriter(object):
    """
2149 2150 2151
    Can be used for writing out some Cython code. To use the indenter
    functionality, the Cython.Compiler.Importer module will have to be used
    to load the code to support python 2.4
2152 2153
    """

2154
    def __init__(self, buffer=None, indent_level=0, context=None, encoding='ascii'):
2155 2156 2157
        self.buffer = buffer or StringIOTree()
        self.level = indent_level
        self.context = context
2158
        self.encoding = encoding
2159 2160 2161

    def indent(self, levels=1):
        self.level += levels
2162
        return True
2163 2164 2165 2166 2167 2168

    def dedent(self, levels=1):
        self.level -= levels

    def indenter(self, line):
        """
2169 2170 2171 2172 2173 2174 2175 2176 2177 2178
        Instead of

            with pyx_code.indenter("for i in range(10):"):
                pyx_code.putln("print i")

        write

            if pyx_code.indenter("for i in range(10);"):
                pyx_code.putln("print i")
                pyx_code.dedent()
2179 2180
        """
        self.putln(line)
2181 2182
        self.indent()
        return True
2183 2184

    def getvalue(self):
2185 2186 2187 2188 2189
        result = self.buffer.getvalue()
        if not isinstance(result, unicode):
            result = result.decode(self.encoding)

        return result
2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215

    def putln(self, line, context=None):
        context = context or self.context
        if context:
            line = sub_tempita(line, context)
        self._putln(line)

    def _putln(self, line):
        self.buffer.write("%s%s\n" % (self.level * "    ", line))

    def put_chunk(self, chunk, context=None):
        context = context or self.context
        if context:
            chunk = sub_tempita(chunk, context)

        chunk = textwrap.dedent(chunk)
        for line in chunk.splitlines():
            self._putln(line)

    def insertion_point(self):
        return PyxCodeWriter(self.buffer.insertion_point(), self.level,
                             self.context)

    def named_insertion_point(self, name):
        setattr(self, name, self.insertion_point())

2216 2217

class ClosureTempAllocator(object):
2218
    def __init__(self, klass):
2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238
        self.klass = klass
        self.temps_allocated = {}
        self.temps_free = {}
        self.temps_count = 0

    def reset(self):
        for type, cnames in self.temps_allocated.items():
            self.temps_free[type] = list(cnames)

    def allocate_temp(self, type):
        if not type in self.temps_allocated:
            self.temps_allocated[type] = []
            self.temps_free[type] = []
        elif self.temps_free[type]:
            return self.temps_free[type].pop(0)
        cname = '%s%d' % (Naming.codewriter_temp_prefix, self.temps_count)
        self.klass.declare_var(pos=None, name=cname, cname=cname, type=type, is_cdef=True)
        self.temps_allocated[type].append(cname)
        self.temps_count += 1
        return cname