diff options
author | orivej <orivej@yandex-team.ru> | 2022-02-10 16:45:01 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:01 +0300 |
commit | 2d37894b1b037cf24231090eda8589bbb44fb6fc (patch) | |
tree | be835aa92c6248212e705f25388ebafcf84bc7a1 /contrib/tools/cython/Cython/Compiler | |
parent | 718c552901d703c502ccbefdfc3c9028d608b947 (diff) | |
download | ydb-2d37894b1b037cf24231090eda8589bbb44fb6fc.tar.gz |
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/tools/cython/Cython/Compiler')
45 files changed, 10056 insertions, 10056 deletions
diff --git a/contrib/tools/cython/Cython/Compiler/Annotate.py b/contrib/tools/cython/Cython/Compiler/Annotate.py index c8a1d9be77..2ea38c00c7 100644 --- a/contrib/tools/cython/Cython/Compiler/Annotate.py +++ b/contrib/tools/cython/Cython/Compiler/Annotate.py @@ -3,21 +3,21 @@ from __future__ import absolute_import import os -import os.path +import os.path import re import codecs import textwrap -from datetime import datetime -from functools import partial -from collections import defaultdict +from datetime import datetime +from functools import partial +from collections import defaultdict try: from xml.sax.saxutils import escape as html_escape except ImportError: pass -try: - from StringIO import StringIO -except ImportError: - from io import StringIO # does not support writing 'str' in Py2 +try: + from StringIO import StringIO +except ImportError: + from io import StringIO # does not support writing 'str' in Py2 from . import Version from .Code import CCodeWriter @@ -27,23 +27,23 @@ from .. import Utils class AnnotationCCodeWriter(CCodeWriter): def __init__(self, create_from=None, buffer=None, copy_formatting=True): - CCodeWriter.__init__(self, create_from, buffer, copy_formatting=copy_formatting) + CCodeWriter.__init__(self, create_from, buffer, copy_formatting=copy_formatting) if create_from is None: self.annotation_buffer = StringIO() - self.last_annotated_pos = None - # annotations[filename][line] -> [(column, AnnotationItem)*] - self.annotations = defaultdict(partial(defaultdict, list)) - # code[filename][line] -> str - self.code = defaultdict(partial(defaultdict, str)) - # scopes[filename][line] -> set(scopes) - self.scopes = defaultdict(partial(defaultdict, set)) + self.last_annotated_pos = None + # annotations[filename][line] -> [(column, AnnotationItem)*] + self.annotations = defaultdict(partial(defaultdict, list)) + # code[filename][line] -> str + self.code = defaultdict(partial(defaultdict, str)) + # scopes[filename][line] -> set(scopes) + self.scopes = defaultdict(partial(defaultdict, set)) else: # When creating an insertion point, keep references to the same database self.annotation_buffer = create_from.annotation_buffer self.annotations = create_from.annotations self.code = create_from.code - self.scopes = create_from.scopes - self.last_annotated_pos = create_from.last_annotated_pos + self.scopes = create_from.scopes + self.last_annotated_pos = create_from.last_annotated_pos def create_new(self, create_from, buffer, copy_formatting): return AnnotationCCodeWriter(create_from, buffer, copy_formatting) @@ -52,54 +52,54 @@ class AnnotationCCodeWriter(CCodeWriter): CCodeWriter.write(self, s) self.annotation_buffer.write(s) - def mark_pos(self, pos, trace=True): + def mark_pos(self, pos, trace=True): if pos is not None: - CCodeWriter.mark_pos(self, pos, trace) - if self.funcstate and self.funcstate.scope: - # lambdas and genexprs can result in multiple scopes per line => keep them in a set - self.scopes[pos[0].filename][pos[1]].add(self.funcstate.scope) - if self.last_annotated_pos: - source_desc, line, _ = self.last_annotated_pos - pos_code = self.code[source_desc.filename] - pos_code[line] += self.annotation_buffer.getvalue() + CCodeWriter.mark_pos(self, pos, trace) + if self.funcstate and self.funcstate.scope: + # lambdas and genexprs can result in multiple scopes per line => keep them in a set + self.scopes[pos[0].filename][pos[1]].add(self.funcstate.scope) + if self.last_annotated_pos: + source_desc, line, _ = self.last_annotated_pos + pos_code = self.code[source_desc.filename] + pos_code[line] += self.annotation_buffer.getvalue() self.annotation_buffer = StringIO() - self.last_annotated_pos = pos + self.last_annotated_pos = pos def annotate(self, pos, item): - self.annotations[pos[0].filename][pos[1]].append((pos[2], item)) + self.annotations[pos[0].filename][pos[1]].append((pos[2], item)) def _css(self): """css template will later allow to choose a colormap""" css = [self._css_template] for i in range(255): color = u"FFFF%02x" % int(255/(1+i/10.0)) - css.append('.cython.score-%d {background-color: #%s;}' % (i, color)) + css.append('.cython.score-%d {background-color: #%s;}' % (i, color)) try: from pygments.formatters import HtmlFormatter except ImportError: pass - else: - css.append(HtmlFormatter().get_style_defs('.cython')) - return '\n'.join(css) + else: + css.append(HtmlFormatter().get_style_defs('.cython')) + return '\n'.join(css) _css_template = textwrap.dedent(""" body.cython { font-family: courier; font-size: 12; } .cython.tag { } .cython.line { margin: 0em } - .cython.code { font-size: 9; color: #444444; display: none; margin: 0px 0px 0px 8px; border-left: 8px none; } + .cython.code { font-size: 9; color: #444444; display: none; margin: 0px 0px 0px 8px; border-left: 8px none; } + + .cython.line .run { background-color: #B0FFB0; } + .cython.line .mis { background-color: #FFB0B0; } + .cython.code.run { border-left: 8px solid #B0FFB0; } + .cython.code.mis { border-left: 8px solid #FFB0B0; } - .cython.line .run { background-color: #B0FFB0; } - .cython.line .mis { background-color: #FFB0B0; } - .cython.code.run { border-left: 8px solid #B0FFB0; } - .cython.code.mis { border-left: 8px solid #FFB0B0; } - .cython.code .py_c_api { color: red; } .cython.code .py_macro_api { color: #FF7000; } .cython.code .pyx_c_api { color: #FF3000; } .cython.code .pyx_macro_api { color: #FF7000; } .cython.code .refnanny { color: #FFA000; } - .cython.code .trace { color: #FFA000; } + .cython.code .trace { color: #FFA000; } .cython.code .error_goto { color: #FFA000; } .cython.code .coerce { color: #008000; border: 1px dotted #008000 } @@ -117,22 +117,22 @@ class AnnotationCCodeWriter(CCodeWriter): ).replace(' ', '') # poor dev's JS minification ) - def save_annotation(self, source_filename, target_filename, coverage_xml=None): + def save_annotation(self, source_filename, target_filename, coverage_xml=None): with Utils.open_source_file(source_filename) as f: code = f.read() generated_code = self.code.get(source_filename, {}) c_file = Utils.decode_filename(os.path.basename(target_filename)) html_filename = os.path.splitext(target_filename)[0] + ".html" - + with codecs.open(html_filename, "w", encoding="UTF-8") as out_buffer: - out_buffer.write(self._save_annotation(code, generated_code, c_file, source_filename, coverage_xml)) - - def _save_annotation_header(self, c_file, source_filename, coverage_timestamp=None): - coverage_info = '' - if coverage_timestamp: - coverage_info = u' with coverage data from {timestamp}'.format( - timestamp=datetime.fromtimestamp(int(coverage_timestamp) // 1000)) - + out_buffer.write(self._save_annotation(code, generated_code, c_file, source_filename, coverage_xml)) + + def _save_annotation_header(self, c_file, source_filename, coverage_timestamp=None): + coverage_info = '' + if coverage_timestamp: + coverage_info = u' with coverage data from {timestamp}'.format( + timestamp=datetime.fromtimestamp(int(coverage_timestamp) // 1000)) + outlist = [ textwrap.dedent(u'''\ <!DOCTYPE html> @@ -140,20 +140,20 @@ class AnnotationCCodeWriter(CCodeWriter): <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> - <title>Cython: {filename}</title> + <title>Cython: {filename}</title> <style type="text/css"> {css} </style> </head> <body class="cython"> - <p><span style="border-bottom: solid 1px grey;">Generated by Cython {watermark}</span>{more_info}</p> - <p> - <span style="background-color: #FFFF00">Yellow lines</span> hint at Python interaction.<br /> - Click on a line that starts with a "<code>+</code>" to see the C code that Cython generated for it. - </p> + <p><span style="border-bottom: solid 1px grey;">Generated by Cython {watermark}</span>{more_info}</p> + <p> + <span style="background-color: #FFFF00">Yellow lines</span> hint at Python interaction.<br /> + Click on a line that starts with a "<code>+</code>" to see the C code that Cython generated for it. + </p> ''').format(css=self._css(), watermark=Version.watermark, - filename=os.path.basename(source_filename) if source_filename else '', - more_info=coverage_info) + filename=os.path.basename(source_filename) if source_filename else '', + more_info=coverage_info) ] if c_file: outlist.append(u'<p>Raw output: <a href="%s">%s</a></p>\n' % (c_file, c_file)) @@ -162,45 +162,45 @@ class AnnotationCCodeWriter(CCodeWriter): def _save_annotation_footer(self): return (u'</body></html>\n',) - def _save_annotation(self, code, generated_code, c_file=None, source_filename=None, coverage_xml=None): + def _save_annotation(self, code, generated_code, c_file=None, source_filename=None, coverage_xml=None): """ lines : original cython source code split by lines generated_code : generated c code keyed by line number in original file target filename : name of the file in which to store the generated html c_file : filename in which the c_code has been written """ - if coverage_xml is not None and source_filename: - coverage_timestamp = coverage_xml.get('timestamp', '').strip() - covered_lines = self._get_line_coverage(coverage_xml, source_filename) - else: - coverage_timestamp = covered_lines = None - annotation_items = dict(self.annotations[source_filename]) - scopes = dict(self.scopes[source_filename]) - + if coverage_xml is not None and source_filename: + coverage_timestamp = coverage_xml.get('timestamp', '').strip() + covered_lines = self._get_line_coverage(coverage_xml, source_filename) + else: + coverage_timestamp = covered_lines = None + annotation_items = dict(self.annotations[source_filename]) + scopes = dict(self.scopes[source_filename]) + outlist = [] - outlist.extend(self._save_annotation_header(c_file, source_filename, coverage_timestamp)) - outlist.extend(self._save_annotation_body(code, generated_code, annotation_items, scopes, covered_lines)) + outlist.extend(self._save_annotation_header(c_file, source_filename, coverage_timestamp)) + outlist.extend(self._save_annotation_body(code, generated_code, annotation_items, scopes, covered_lines)) outlist.extend(self._save_annotation_footer()) return ''.join(outlist) - def _get_line_coverage(self, coverage_xml, source_filename): - coverage_data = None - for entry in coverage_xml.iterfind('.//class'): - if not entry.get('filename'): - continue - if (entry.get('filename') == source_filename or - os.path.abspath(entry.get('filename')) == source_filename): - coverage_data = entry - break - elif source_filename.endswith(entry.get('filename')): - coverage_data = entry # but we might still find a better match... - if coverage_data is None: - return None - return dict( - (int(line.get('number')), int(line.get('hits'))) - for line in coverage_data.iterfind('lines/line') - ) - + def _get_line_coverage(self, coverage_xml, source_filename): + coverage_data = None + for entry in coverage_xml.iterfind('.//class'): + if not entry.get('filename'): + continue + if (entry.get('filename') == source_filename or + os.path.abspath(entry.get('filename')) == source_filename): + coverage_data = entry + break + elif source_filename.endswith(entry.get('filename')): + coverage_data = entry # but we might still find a better match... + if coverage_data is None: + return None + return dict( + (int(line.get('number')), int(line.get('hits'))) + for line in coverage_data.iterfind('lines/line') + ) + def _htmlify_code(self, code): try: from pygments import highlight @@ -215,12 +215,12 @@ class AnnotationCCodeWriter(CCodeWriter): HtmlFormatter(nowrap=True)) return html_code - def _save_annotation_body(self, cython_code, generated_code, annotation_items, scopes, covered_lines=None): + def _save_annotation_body(self, cython_code, generated_code, annotation_items, scopes, covered_lines=None): outlist = [u'<div class="cython">'] pos_comment_marker = u'/* \N{HORIZONTAL ELLIPSIS} */\n' new_calls_map = dict( (name, 0) for name in - 'refnanny trace py_macro_api py_c_api pyx_macro_api pyx_c_api error_goto'.split() + 'refnanny trace py_macro_api py_c_api pyx_macro_api pyx_c_api error_goto'.split() ).copy self.mark_pos(None) @@ -228,13 +228,13 @@ class AnnotationCCodeWriter(CCodeWriter): def annotate(match): group_name = match.lastgroup calls[group_name] += 1 - return u"<span class='%s'>%s</span>" % ( + return u"<span class='%s'>%s</span>" % ( group_name, match.group(group_name)) lines = self._htmlify_code(cython_code).splitlines() lineno_width = len(str(len(lines))) - if not covered_lines: - covered_lines = None + if not covered_lines: + covered_lines = None for k, line in enumerate(lines, 1): try: @@ -259,48 +259,48 @@ class AnnotationCCodeWriter(CCodeWriter): onclick = '' expandsymbol = ' ' - covered = '' - if covered_lines is not None and k in covered_lines: - hits = covered_lines[k] - if hits is not None: - covered = 'run' if hits else 'mis' - + covered = '' + if covered_lines is not None and k in covered_lines: + hits = covered_lines[k] + if hits is not None: + covered = 'run' if hits else 'mis' + outlist.append( - u'<pre class="cython line score-{score}"{onclick}>' + u'<pre class="cython line score-{score}"{onclick}>' # generate line number with expand symbol in front, # and the right number of digit - u'{expandsymbol}<span class="{covered}">{line:0{lineno_width}d}</span>: {code}</pre>\n'.format( + u'{expandsymbol}<span class="{covered}">{line:0{lineno_width}d}</span>: {code}</pre>\n'.format( score=score, expandsymbol=expandsymbol, - covered=covered, + covered=covered, lineno_width=lineno_width, line=k, code=line.rstrip(), onclick=onclick, )) if c_code: - outlist.append(u"<pre class='cython code score-{score} {covered}'>{code}</pre>".format( - score=score, covered=covered, code=c_code)) + outlist.append(u"<pre class='cython code score-{score} {covered}'>{code}</pre>".format( + score=score, covered=covered, code=c_code)) outlist.append(u"</div>") return outlist -_parse_code = re.compile(( - br'(?P<refnanny>__Pyx_X?(?:GOT|GIVE)REF|__Pyx_RefNanny[A-Za-z]+)|' - br'(?P<trace>__Pyx_Trace[A-Za-z]+)|' - br'(?:' - br'(?P<pyx_macro_api>__Pyx_[A-Z][A-Z_]+)|' - br'(?P<pyx_c_api>(?:__Pyx_[A-Z][a-z_][A-Za-z_]*)|__pyx_convert_[A-Za-z_]*)|' - br'(?P<py_macro_api>Py[A-Z][a-z]+_[A-Z][A-Z_]+)|' - br'(?P<py_c_api>Py[A-Z][a-z]+_[A-Z][a-z][A-Za-z_]*)' - br')(?=\()|' # look-ahead to exclude subsequent '(' from replacement +_parse_code = re.compile(( + br'(?P<refnanny>__Pyx_X?(?:GOT|GIVE)REF|__Pyx_RefNanny[A-Za-z]+)|' + br'(?P<trace>__Pyx_Trace[A-Za-z]+)|' + br'(?:' + br'(?P<pyx_macro_api>__Pyx_[A-Z][A-Z_]+)|' + br'(?P<pyx_c_api>(?:__Pyx_[A-Z][a-z_][A-Za-z_]*)|__pyx_convert_[A-Za-z_]*)|' + br'(?P<py_macro_api>Py[A-Z][a-z]+_[A-Z][A-Z_]+)|' + br'(?P<py_c_api>Py[A-Z][a-z]+_[A-Z][a-z][A-Za-z_]*)' + br')(?=\()|' # look-ahead to exclude subsequent '(' from replacement br'(?P<error_goto>(?:(?<=;) *if [^;]* +)?__PYX_ERR\([^)]+\))' -).decode('ascii')).sub +).decode('ascii')).sub _replace_pos_comment = re.compile( # this matches what Cython generates as code line marker comment - br'^\s*/\*(?:(?:[^*]|\*[^/])*\n)+\s*\*/\s*\n'.decode('ascii'), + br'^\s*/\*(?:(?:[^*]|\*[^/])*\n)+\s*\*/\s*\n'.decode('ascii'), re.M ).sub diff --git a/contrib/tools/cython/Cython/Compiler/AutoDocTransforms.py b/contrib/tools/cython/Cython/Compiler/AutoDocTransforms.py index 321bac6fba..d3c0a1d0da 100644 --- a/contrib/tools/cython/Cython/Compiler/AutoDocTransforms.py +++ b/contrib/tools/cython/Cython/Compiler/AutoDocTransforms.py @@ -167,7 +167,7 @@ class EmbedSignature(CythonTransform): old_doc = node.py_func.entry.doc else: old_doc = None - new_doc = self._embed_signature(signature, old_doc) + new_doc = self._embed_signature(signature, old_doc) doc_holder.doc = EncodedString(new_doc) if not is_constructor and getattr(node, 'py_func', None) is not None: node.py_func.entry.doc = EncodedString(new_doc) diff --git a/contrib/tools/cython/Cython/Compiler/Buffer.py b/contrib/tools/cython/Cython/Compiler/Buffer.py index 7c9a13fcea..c62a24f568 100644 --- a/contrib/tools/cython/Cython/Compiler/Buffer.py +++ b/contrib/tools/cython/Cython/Compiler/Buffer.py @@ -47,22 +47,22 @@ class IntroduceBufferAuxiliaryVars(CythonTransform): # For all buffers, insert extra variables in the scope. # The variables are also accessible from the buffer_info # on the buffer entry - scope_items = scope.entries.items() - bufvars = [entry for name, entry in scope_items if entry.type.is_buffer] + scope_items = scope.entries.items() + bufvars = [entry for name, entry in scope_items if entry.type.is_buffer] if len(bufvars) > 0: bufvars.sort(key=lambda entry: entry.name) self.buffers_exists = True - memviewslicevars = [entry for name, entry in scope_items if entry.type.is_memoryviewslice] + memviewslicevars = [entry for name, entry in scope_items if entry.type.is_memoryviewslice] if len(memviewslicevars) > 0: self.buffers_exists = True - for (name, entry) in scope_items: + for (name, entry) in scope_items: if name == 'memoryview' and isinstance(entry.utility_code_definition, CythonUtilityCode): self.using_memoryview = True break - del scope_items + del scope_items if isinstance(node, ModuleNode) and len(bufvars) > 0: # for now...note that pos is wrong @@ -138,14 +138,14 @@ def analyse_buffer_options(globalpos, env, posargs, dictargs, defaults=None, nee if defaults is None: defaults = buffer_defaults - posargs, dictargs = Interpreter.interpret_compiletime_options( - posargs, dictargs, type_env=env, type_args=(0, 'dtype')) + posargs, dictargs = Interpreter.interpret_compiletime_options( + posargs, dictargs, type_env=env, type_args=(0, 'dtype')) if len(posargs) > buffer_positional_options_count: raise CompileError(posargs[-1][1], ERR_BUF_TOO_MANY) options = {} - for name, (value, pos) in dictargs.items(): + for name, (value, pos) in dictargs.items(): if not name in buffer_options: raise CompileError(pos, ERR_BUF_OPTION_UNKNOWN % name) options[name] = value @@ -199,14 +199,14 @@ class BufferEntry(object): self.type = entry.type self.cname = entry.buffer_aux.buflocal_nd_var.cname self.buf_ptr = "%s.rcbuffer->pybuffer.buf" % self.cname - self.buf_ptr_type = entry.type.buffer_ptr_type - self.init_attributes() - - def init_attributes(self): - self.shape = self.get_buf_shapevars() - self.strides = self.get_buf_stridevars() - self.suboffsets = self.get_buf_suboffsetvars() - + self.buf_ptr_type = entry.type.buffer_ptr_type + self.init_attributes() + + def init_attributes(self): + self.shape = self.get_buf_shapevars() + self.strides = self.get_buf_stridevars() + self.suboffsets = self.get_buf_suboffsetvars() + def get_buf_suboffsetvars(self): return self._for_all_ndim("%s.diminfo[%d].suboffsets") @@ -258,7 +258,7 @@ class BufferEntry(object): defcode = code.globalstate['utility_code_def'] funcgen(protocode, defcode, name=funcname, nd=nd) - buf_ptr_type_code = self.buf_ptr_type.empty_declaration_code() + buf_ptr_type_code = self.buf_ptr_type.empty_declaration_code() ptrcode = "%s(%s, %s, %s)" % (funcname, buf_ptr_type_code, self.buf_ptr, ", ".join(params)) return ptrcode @@ -421,7 +421,7 @@ def put_assign_to_buffer(lhs_cname, rhs_cname, buf_entry, code.putln("}") # Release stack - + def put_buffer_lookup_code(entry, index_signeds, index_cnames, directives, pos, code, negative_indices, in_nogil_context): """ @@ -442,21 +442,21 @@ def put_buffer_lookup_code(entry, index_signeds, index_cnames, directives, if directives['boundscheck']: # Check bounds and fix negative indices. # We allocate a temporary which is initialized to -1, meaning OK (!). - # If an error occurs, the temp is set to the index dimension the - # error is occurring at. - failed_dim_temp = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False) - code.putln("%s = -1;" % failed_dim_temp) - for dim, (signed, cname, shape) in enumerate(zip(index_signeds, index_cnames, entry.get_buf_shapevars())): + # If an error occurs, the temp is set to the index dimension the + # error is occurring at. + failed_dim_temp = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False) + code.putln("%s = -1;" % failed_dim_temp) + for dim, (signed, cname, shape) in enumerate(zip(index_signeds, index_cnames, entry.get_buf_shapevars())): if signed != 0: # not unsigned, deal with negative index code.putln("if (%s < 0) {" % cname) if negative_indices: code.putln("%s += %s;" % (cname, shape)) code.putln("if (%s) %s = %d;" % ( - code.unlikely("%s < 0" % cname), - failed_dim_temp, dim)) + code.unlikely("%s < 0" % cname), + failed_dim_temp, dim)) else: - code.putln("%s = %d;" % (failed_dim_temp, dim)) + code.putln("%s = %d;" % (failed_dim_temp, dim)) code.put("} else ") # check bounds in positive direction if signed != 0: @@ -465,7 +465,7 @@ def put_buffer_lookup_code(entry, index_signeds, index_cnames, directives, cast = "(size_t)" code.putln("if (%s) %s = %d;" % ( code.unlikely("%s >= %s%s" % (cname, cast, shape)), - failed_dim_temp, dim)) + failed_dim_temp, dim)) if in_nogil_context: code.globalstate.use_utility_code(raise_indexerror_nogil) @@ -474,14 +474,14 @@ def put_buffer_lookup_code(entry, index_signeds, index_cnames, directives, code.globalstate.use_utility_code(raise_indexerror_code) func = '__Pyx_RaiseBufferIndexError' - code.putln("if (%s) {" % code.unlikely("%s != -1" % failed_dim_temp)) - code.putln('%s(%s);' % (func, failed_dim_temp)) + code.putln("if (%s) {" % code.unlikely("%s != -1" % failed_dim_temp)) + code.putln('%s(%s);' % (func, failed_dim_temp)) code.putln(code.error_goto(pos)) code.putln('}') - code.funcstate.release_temp(failed_dim_temp) + code.funcstate.release_temp(failed_dim_temp) elif negative_indices: # Only fix negative indices. - for signed, cname, shape in zip(index_signeds, index_cnames, entry.get_buf_shapevars()): + for signed, cname, shape in zip(index_signeds, index_cnames, entry.get_buf_shapevars()): if signed != 0: code.putln("if (%s < 0) %s += %s;" % (cname, cname, shape)) @@ -571,14 +571,14 @@ class GetAndReleaseBufferUtilityCode(object): def __hash__(self): return 24342342 - def get_tree(self, **kwargs): pass + def get_tree(self, **kwargs): pass def put_code(self, output): code = output['utility_code_def'] proto_code = output['utility_code_proto'] env = output.module_node.scope cython_scope = env.context.cython_scope - + # Search all types for __getbuffer__ overloads types = [] visited_scopes = set() @@ -628,7 +628,7 @@ def mangle_dtype_name(dtype): prefix = "nn_" else: prefix = "" - return prefix + dtype.specialization_name() + return prefix + dtype.specialization_name() def get_type_information_cname(code, dtype, maxdepth=None): """ @@ -664,7 +664,7 @@ def get_type_information_cname(code, dtype, maxdepth=None): complex_possible = dtype.is_struct_or_union and dtype.can_be_complex() - declcode = dtype.empty_declaration_code() + declcode = dtype.empty_declaration_code() if dtype.is_simple_buffer_dtype(): structinfo_name = "NULL" elif dtype.is_struct: @@ -679,7 +679,7 @@ def get_type_information_cname(code, dtype, maxdepth=None): typecode.putln("static __Pyx_StructField %s[] = {" % structinfo_name, safe=True) for f, typeinfo in zip(fields, types): typecode.putln(' {&%s, "%s", offsetof(%s, %s)},' % - (typeinfo, f.name, dtype.empty_declaration_code(), f.cname), safe=True) + (typeinfo, f.name, dtype.empty_declaration_code(), f.cname), safe=True) typecode.putln(' {NULL, NULL, 0}', safe=True) typecode.putln("};", safe=True) else: diff --git a/contrib/tools/cython/Cython/Compiler/Builtin.py b/contrib/tools/cython/Cython/Compiler/Builtin.py index 32cb3e0e91..5fa717507d 100644 --- a/contrib/tools/cython/Cython/Compiler/Builtin.py +++ b/contrib/tools/cython/Cython/Compiler/Builtin.py @@ -124,12 +124,12 @@ builtin_function_table = [ PyrexTypes.c_double_complex_type, PyrexTypes.c_longdouble_complex_type) ) + [ - BuiltinFunction('abs', "O", "O", "__Pyx_PyNumber_Absolute", - utility_code=UtilityCode.load("py_abs", "Builtins.c")), - #('all', "", "", ""), - #('any', "", "", ""), - #('ascii', "", "", ""), - #('bin', "", "", ""), + BuiltinFunction('abs', "O", "O", "__Pyx_PyNumber_Absolute", + utility_code=UtilityCode.load("py_abs", "Builtins.c")), + #('all', "", "", ""), + #('any', "", "", ""), + #('ascii', "", "", ""), + #('bin', "", "", ""), BuiltinFunction('callable', "O", "b", "__Pyx_PyCallable_Check", utility_code = UtilityCode.load("CallableCheck", "ObjectHandling.c")), #('chr', "", "", ""), @@ -176,26 +176,26 @@ builtin_function_table = [ utility_code = iter_next_utility_code), # not available in Py2 => implemented here #('oct', "", "", ""), #('open', "ss", "O", "PyFile_FromString"), # not in Py3 -] + [ - BuiltinFunction('ord', None, None, "__Pyx_long_cast", - func_type=PyrexTypes.CFuncType( - PyrexTypes.c_long_type, [PyrexTypes.CFuncTypeArg("c", c_type, None)], - is_strict_signature=True)) - for c_type in [PyrexTypes.c_py_ucs4_type, PyrexTypes.c_py_unicode_type] -] + [ - BuiltinFunction('ord', None, None, "__Pyx_uchar_cast", - func_type=PyrexTypes.CFuncType( - PyrexTypes.c_uchar_type, [PyrexTypes.CFuncTypeArg("c", c_type, None)], - is_strict_signature=True)) - for c_type in [PyrexTypes.c_char_type, PyrexTypes.c_schar_type, PyrexTypes.c_uchar_type] -] + [ - BuiltinFunction('ord', None, None, "__Pyx_PyObject_Ord", - utility_code=UtilityCode.load_cached("object_ord", "Builtins.c"), - func_type=PyrexTypes.CFuncType( - PyrexTypes.c_long_type, [ - PyrexTypes.CFuncTypeArg("c", PyrexTypes.py_object_type, None) - ], - exception_value="(long)(Py_UCS4)-1")), +] + [ + BuiltinFunction('ord', None, None, "__Pyx_long_cast", + func_type=PyrexTypes.CFuncType( + PyrexTypes.c_long_type, [PyrexTypes.CFuncTypeArg("c", c_type, None)], + is_strict_signature=True)) + for c_type in [PyrexTypes.c_py_ucs4_type, PyrexTypes.c_py_unicode_type] +] + [ + BuiltinFunction('ord', None, None, "__Pyx_uchar_cast", + func_type=PyrexTypes.CFuncType( + PyrexTypes.c_uchar_type, [PyrexTypes.CFuncTypeArg("c", c_type, None)], + is_strict_signature=True)) + for c_type in [PyrexTypes.c_char_type, PyrexTypes.c_schar_type, PyrexTypes.c_uchar_type] +] + [ + BuiltinFunction('ord', None, None, "__Pyx_PyObject_Ord", + utility_code=UtilityCode.load_cached("object_ord", "Builtins.c"), + func_type=PyrexTypes.CFuncType( + PyrexTypes.c_long_type, [ + PyrexTypes.CFuncTypeArg("c", PyrexTypes.py_object_type, None) + ], + exception_value="(long)(Py_UCS4)-1")), BuiltinFunction('pow', "OOO", "O", "PyNumber_Power"), BuiltinFunction('pow', "OO", "O", "__Pyx_PyNumber_Power2", utility_code = UtilityCode.load("pow2", "Builtins.c")), @@ -207,7 +207,7 @@ builtin_function_table = [ #('round', "", "", ""), BuiltinFunction('setattr', "OOO", "r", "PyObject_SetAttr"), #('sum', "", "", ""), - #('sorted', "", "", ""), + #('sorted', "", "", ""), #('type', "O", "O", "PyObject_Type"), #('unichr', "", "", ""), #('unicode', "", "", ""), @@ -219,10 +219,10 @@ builtin_function_table = [ # Put in namespace append optimization. BuiltinFunction('__Pyx_PyObject_Append', "OO", "O", "__Pyx_PyObject_Append"), - - # This is conditionally looked up based on a compiler directive. - BuiltinFunction('__Pyx_Globals', "", "O", "__Pyx_Globals", - utility_code=globals_utility_code), + + # This is conditionally looked up based on a compiler directive. + BuiltinFunction('__Pyx_Globals', "", "O", "__Pyx_Globals", + utility_code=globals_utility_code), ] @@ -339,7 +339,7 @@ builtin_types_table = [ BuiltinMethod("add", "TO", "r", "PySet_Add"), BuiltinMethod("pop", "T", "O", "PySet_Pop")]), ("frozenset", "PyFrozenSet_Type", []), - ("Exception", "((PyTypeObject*)PyExc_Exception)[0]", []), + ("Exception", "((PyTypeObject*)PyExc_Exception)[0]", []), ("StopAsyncIteration", "((PyTypeObject*)__Pyx_PyExc_StopAsyncIteration)[0]", []), ] @@ -396,8 +396,8 @@ def init_builtin_types(): objstruct_cname = 'PyByteArrayObject' elif name == 'bool': objstruct_cname = None - elif name == 'Exception': - objstruct_cname = "PyBaseExceptionObject" + elif name == 'Exception': + objstruct_cname = "PyBaseExceptionObject" elif name == 'StopAsyncIteration': objstruct_cname = "PyBaseExceptionObject" else: @@ -421,11 +421,11 @@ def init_builtins(): init_builtin_structs() init_builtin_types() init_builtin_funcs() - + builtin_scope.declare_var( '__debug__', PyrexTypes.c_const_type(PyrexTypes.c_bint_type), pos=None, cname='(!Py_OptimizeFlag)', is_cdef=True) - + global list_type, tuple_type, dict_type, set_type, frozenset_type global bytes_type, str_type, unicode_type, basestring_type, slice_type global float_type, bool_type, type_type, complex_type, bytearray_type diff --git a/contrib/tools/cython/Cython/Compiler/CmdLine.py b/contrib/tools/cython/Cython/Compiler/CmdLine.py index 6ddc14d76f..a20ab38dc2 100644 --- a/contrib/tools/cython/Cython/Compiler/CmdLine.py +++ b/contrib/tools/cython/Cython/Compiler/CmdLine.py @@ -34,14 +34,14 @@ Options: -D, --no-docstrings Strip docstrings from the compiled module. -a, --annotate Produce a colorized HTML version of the source. - --annotate-coverage <cov.xml> Annotate and include coverage information from cov.xml. + --annotate-coverage <cov.xml> Annotate and include coverage information from cov.xml. --line-directives Produce #line directives pointing to the .pyx source --cplus Output a C++ rather than C file. --embed[=<method_name>] Generate a main() function that embeds the Python interpreter. -2 Compile based on Python-2 syntax and code semantics. -3 Compile based on Python-3 syntax and code semantics. - --3str Compile based on Python-3 syntax and code semantics without - assuming unicode by default for string literals under Python 2. + --3str Compile based on Python-3 syntax and code semantics without + assuming unicode by default for string literals under Python 2. --lenient Change some compile time errors to runtime errors to improve Python compatibility --capi-reexport-cincludes Add cincluded headers to any auto-generated header files. @@ -49,11 +49,11 @@ Options: --warning-errors, -Werror Make all warnings into errors --warning-extra, -Wextra Enable extra warnings -X, --directive <name>=<value>[,<name=value,...] Overrides a compiler directive - -E, --compile-time-env name=value[,<name=value,...] Provides compile time env like DEF would do. + -E, --compile-time-env name=value[,<name=value,...] Provides compile time env like DEF would do. """ -# The following experimental options are supported only on MacOSX: +# The following experimental options are supported only on MacOSX: # -C, --compile Compile generated .c file to .o file # --link Link .o file to produce extension module (implies -C) # -+, --cplus Use C++ compiler for compiling and linking @@ -67,26 +67,26 @@ def bad_usage(): def parse_command_line(args): from .Main import CompilationOptions, default_options - pending_arg = [] - + pending_arg = [] + def pop_arg(): - if not args or pending_arg: + if not args or pending_arg: + bad_usage() + if '=' in args[0] and args[0].startswith('--'): # allow "--long-option=xyz" + name, value = args.pop(0).split('=', 1) + pending_arg.append(value) + return name + return args.pop(0) + + def pop_value(default=None): + if pending_arg: + return pending_arg.pop() + elif default is not None: + return default + elif not args: bad_usage() - if '=' in args[0] and args[0].startswith('--'): # allow "--long-option=xyz" - name, value = args.pop(0).split('=', 1) - pending_arg.append(value) - return name - return args.pop(0) - - def pop_value(default=None): - if pending_arg: - return pending_arg.pop() - elif default is not None: - return default - elif not args: - bad_usage() - return args.pop(0) - + return args.pop(0) + def get_param(option): tail = option[2:] if tail: @@ -106,15 +106,15 @@ def parse_command_line(args): elif option in ("-+", "--cplus"): options.cplus = 1 elif option == "--embed": - Options.embed = pop_value("main") + Options.embed = pop_value("main") elif option.startswith("-I"): options.include_path.append(get_param(option)) elif option == "--include-dir": - options.include_path.append(pop_value()) + options.include_path.append(pop_value()) elif option in ("-w", "--working"): - options.working_path = pop_value() + options.working_path = pop_value() elif option in ("-o", "--output-file"): - options.output_file = pop_value() + options.output_file = pop_value() elif option in ("-t", "--timestamps"): options.timestamps = 1 elif option in ("-f", "--force"): @@ -124,16 +124,16 @@ def parse_command_line(args): elif option in ("-p", "--embed-positions"): Options.embed_pos_in_docstring = 1 elif option in ("-z", "--pre-import"): - Options.pre_import = pop_value() + Options.pre_import = pop_value() elif option == "--cleanup": - Options.generate_cleanup_code = int(pop_value()) + Options.generate_cleanup_code = int(pop_value()) elif option in ("-D", "--no-docstrings"): Options.docstrings = False elif option in ("-a", "--annotate"): Options.annotate = True - elif option == "--annotate-coverage": - Options.annotate = True - Options.annotate_coverage_xml = pop_value() + elif option == "--annotate-coverage": + Options.annotate = True + Options.annotate_coverage_xml = pop_value() elif option == "--convert-range": Options.convert_range = True elif option == "--line-directives": @@ -145,22 +145,22 @@ def parse_command_line(args): options.output_dir = os.curdir elif option == "--gdb-outdir": options.gdb_debug = True - options.output_dir = pop_value() + options.output_dir = pop_value() elif option == "--lenient": Options.error_on_unknown_names = False Options.error_on_uninitialized = False - elif option == '--module-name': - options.module_name = pop_arg() - elif option == '--init-suffix': - options.init_suffix = pop_arg() + elif option == '--module-name': + options.module_name = pop_arg() + elif option == '--init-suffix': + options.init_suffix = pop_arg() elif option == '--source-root': Options.source_root = pop_arg() elif option == '-2': options.language_level = 2 elif option == '-3': options.language_level = 3 - elif option == '--3str': - options.language_level = '3str' + elif option == '--3str': + options.language_level = '3str' elif option == "--capi-reexport-cincludes": options.capi_reexport_cincludes = True elif option == "--fast-fail": @@ -177,25 +177,25 @@ def parse_command_line(args): if option.startswith('-X') and option[2:].strip(): x_args = option[2:] else: - x_args = pop_value() + x_args = pop_value() try: options.compiler_directives = Options.parse_directive_list( x_args, relaxed_bool=True, current_settings=options.compiler_directives) - except ValueError as e: + except ValueError as e: sys.stderr.write("Error in compiler directive: %s\n" % e.args[0]) sys.exit(1) - elif option == "--compile-time-env" or option.startswith('-E'): - if option.startswith('-E') and option[2:].strip(): - x_args = option[2:] - else: - x_args = pop_value() - try: - options.compile_time_env = Options.parse_compile_time_env( - x_args, current_settings=options.compile_time_env) - except ValueError as e: - sys.stderr.write("Error in compile-time-env: %s\n" % e.args[0]) - sys.exit(1) + elif option == "--compile-time-env" or option.startswith('-E'): + if option.startswith('-E') and option[2:].strip(): + x_args = option[2:] + else: + x_args = pop_value() + try: + options.compile_time_env = Options.parse_compile_time_env( + x_args, current_settings=options.compile_time_env) + except ValueError as e: + sys.stderr.write("Error in compile-time-env: %s\n" % e.args[0]) + sys.exit(1) elif option.startswith('--debug'): option = option[2:].replace('-', '_') from . import DebugFlags @@ -212,10 +212,10 @@ def parse_command_line(args): sys.exit(1) else: sources.append(pop_arg()) - - if pending_arg: - bad_usage() - + + if pending_arg: + bad_usage() + if options.use_listing_file and len(sources) > 1: sys.stderr.write( "cython: Only one source file allowed when using -o\n") diff --git a/contrib/tools/cython/Cython/Compiler/Code.pxd b/contrib/tools/cython/Cython/Compiler/Code.pxd index 4c0e27f15f..acad0c1cf4 100644 --- a/contrib/tools/cython/Cython/Compiler/Code.pxd +++ b/contrib/tools/cython/Cython/Compiler/Code.pxd @@ -2,7 +2,7 @@ from __future__ import absolute_import cimport cython -from ..StringIOTree cimport StringIOTree +from ..StringIOTree cimport StringIOTree cdef class UtilityCodeBase(object): @@ -27,7 +27,7 @@ cdef class UtilityCode(UtilityCodeBase): cdef class FunctionState: cdef public set names_taken cdef public object owner - cdef public object scope + cdef public object scope cdef public object error_label cdef public size_t label_counter @@ -39,11 +39,11 @@ cdef class FunctionState: cdef public object return_from_error_cleanup_label # not used in __init__ ? - cdef public object exc_vars + cdef public object exc_vars cdef public object current_except cdef public bint in_try_finally cdef public bint can_trace - cdef public bint gil_owned + cdef public bint gil_owned cdef public list temps_allocated cdef public dict temps_free @@ -97,28 +97,28 @@ cdef class StringConst: #def funccontext_property(name): -cdef class CCodeWriter(object): - cdef readonly StringIOTree buffer - cdef readonly list pyclass_stack - cdef readonly object globalstate - cdef readonly object funcstate - cdef object code_config - cdef object last_pos - cdef object last_marked_pos - cdef Py_ssize_t level - cdef public Py_ssize_t call_level # debug-only, see Nodes.py - cdef bint bol - - cpdef write(self, s) - cpdef put(self, code) - cpdef put_safe(self, code) - cpdef putln(self, code=*, bint safe=*) - @cython.final - cdef increase_indent(self) - @cython.final - cdef decrease_indent(self) - - +cdef class CCodeWriter(object): + cdef readonly StringIOTree buffer + cdef readonly list pyclass_stack + cdef readonly object globalstate + cdef readonly object funcstate + cdef object code_config + cdef object last_pos + cdef object last_marked_pos + cdef Py_ssize_t level + cdef public Py_ssize_t call_level # debug-only, see Nodes.py + cdef bint bol + + cpdef write(self, s) + cpdef put(self, code) + cpdef put_safe(self, code) + cpdef putln(self, code=*, bint safe=*) + @cython.final + cdef increase_indent(self) + @cython.final + cdef decrease_indent(self) + + cdef class PyrexCodeWriter: cdef public object f cdef public Py_ssize_t level diff --git a/contrib/tools/cython/Cython/Compiler/Code.py b/contrib/tools/cython/Cython/Compiler/Code.py index 97e97a12d3..f43c4b2b8e 100644 --- a/contrib/tools/cython/Cython/Compiler/Code.py +++ b/contrib/tools/cython/Cython/Compiler/Code.py @@ -1,5 +1,5 @@ # cython: language_level = 2 -# cython: auto_pickle=False +# cython: auto_pickle=False # # Code output module # @@ -19,10 +19,10 @@ import shutil import sys import operator import textwrap -from string import Template -from functools import partial -from contextlib import closing -from collections import defaultdict +from string import Template +from functools import partial +from contextlib import closing +from collections import defaultdict try: import hashlib @@ -33,7 +33,7 @@ from . import Naming from . import Options from . import DebugFlags from . import StringEncoding -from . import Version +from . import Version from .. import Utils from .Scanning import SourceDescriptor from ..StringIOTree import StringIOTree @@ -43,7 +43,7 @@ try: except ImportError: from builtins import str as basestring -KEYWORDS_MUST_BE_BYTES = sys.version_info < (2, 7) +KEYWORDS_MUST_BE_BYTES = sys.version_info < (2, 7) non_portable_builtins_map = { @@ -53,22 +53,22 @@ non_portable_builtins_map = { 'basestring' : ('PY_MAJOR_VERSION >= 3', 'str'), 'xrange' : ('PY_MAJOR_VERSION >= 3', 'range'), 'raw_input' : ('PY_MAJOR_VERSION >= 3', 'input'), -} - -ctypedef_builtins_map = { - # types of builtins in "ctypedef class" statements which we don't - # import either because the names conflict with C types or because - # the type simply is not exposed. - 'py_int' : '&PyInt_Type', - 'py_long' : '&PyLong_Type', - 'py_float' : '&PyFloat_Type', - 'wrapper_descriptor' : '&PyWrapperDescr_Type', -} - +} + +ctypedef_builtins_map = { + # types of builtins in "ctypedef class" statements which we don't + # import either because the names conflict with C types or because + # the type simply is not exposed. + 'py_int' : '&PyInt_Type', + 'py_long' : '&PyLong_Type', + 'py_float' : '&PyFloat_Type', + 'wrapper_descriptor' : '&PyWrapperDescr_Type', +} + basicsize_builtins_map = { # builtins whose type has a different tp_basicsize than sizeof(...) - 'PyTypeObject': 'PyHeapTypeObject', -} + 'PyTypeObject': 'PyHeapTypeObject', +} uncachable_builtins = [ # Global/builtin names that cannot be cached because they may or may not @@ -107,15 +107,15 @@ uncachable_builtins = [ 'WindowsError', ## - others '_', # e.g. used by gettext -] - -special_py_methods = set([ - '__cinit__', '__dealloc__', '__richcmp__', '__next__', - '__await__', '__aiter__', '__anext__', - '__getreadbuffer__', '__getwritebuffer__', '__getsegcount__', - '__getcharbuffer__', '__getbuffer__', '__releasebuffer__' -]) - +] + +special_py_methods = set([ + '__cinit__', '__dealloc__', '__richcmp__', '__next__', + '__await__', '__aiter__', '__anext__', + '__getreadbuffer__', '__getwritebuffer__', '__getsegcount__', + '__getcharbuffer__', '__getbuffer__', '__releasebuffer__' +]) + modifier_output_mapper = { 'inline': 'CYTHON_INLINE' }.get @@ -246,7 +246,7 @@ class UtilityCodeBase(object): del tags['substitute'] try: code = Template(code).substitute(vars(Naming)) - except (KeyError, ValueError) as e: + except (KeyError, ValueError) as e: raise RuntimeError("Error parsing templated utility code of type '%s' at line %d: %s" % ( type, begin_lineno, e)) @@ -281,23 +281,23 @@ class UtilityCodeBase(object): if ext in ('.pyx', '.py', '.pxd', '.pxi'): comment = '#' strip_comments = partial(re.compile(r'^\s*#(?!\s*cython\s*:).*').sub, '') - rstrip = StringEncoding._unicode.rstrip + rstrip = StringEncoding._unicode.rstrip else: comment = '/' - strip_comments = partial(re.compile(r'^\s*//.*|/\*[^*]*\*/').sub, '') - rstrip = partial(re.compile(r'\s+(\\?)$').sub, r'\1') + strip_comments = partial(re.compile(r'^\s*//.*|/\*[^*]*\*/').sub, '') + rstrip = partial(re.compile(r'\s+(\\?)$').sub, r'\1') match_special = re.compile( (r'^%(C)s{5,30}\s*(?P<name>(?:\w|\.)+)\s*%(C)s{5,30}|' - r'^%(C)s+@(?P<tag>\w+)\s*:\s*(?P<value>(?:\w|[.:])+)') % - {'C': comment}).match - match_type = re.compile(r'(.+)[.](proto(?:[.]\S+)?|impl|init|cleanup)$').match + r'^%(C)s+@(?P<tag>\w+)\s*:\s*(?P<value>(?:\w|[.:])+)') % + {'C': comment}).match + match_type = re.compile(r'(.+)[.](proto(?:[.]\S+)?|impl|init|cleanup)$').match - with closing(Utils.open_source_file(filename, encoding='UTF-8')) as f: + with closing(Utils.open_source_file(filename, encoding='UTF-8')) as f: all_lines = f.readlines() utilities = defaultdict(lambda: [None, None, {}]) lines = [] - tags = defaultdict(set) + tags = defaultdict(set) utility = type = None begin_lineno = 0 @@ -317,12 +317,12 @@ class UtilityCodeBase(object): name, type = mtype.groups() else: type = 'impl' - utility = utilities[name] + utility = utilities[name] else: - tags[m.group('tag')].add(m.group('value')) - lines.append('') # keep line number correct + tags[m.group('tag')].add(m.group('value')) + lines.append('') # keep line number correct else: - lines.append(rstrip(strip_comments(line))) + lines.append(rstrip(strip_comments(line))) if utility is None: raise ValueError("Empty utility code file") @@ -330,7 +330,7 @@ class UtilityCodeBase(object): # Don't forget to add the last utility code cls._add_utility(utility, type, lines, begin_lineno, tags) - utilities = dict(utilities) # un-defaultdict-ify + utilities = dict(utilities) # un-defaultdict-ify cls._utility_cache[path] = utilities return utilities @@ -356,12 +356,12 @@ class UtilityCodeBase(object): global __loader__ loader = __loader__ archive = loader.archive - with closing(zipfile.ZipFile(archive)) as fileobj: - listing = [os.path.basename(name) - for name in fileobj.namelist() - if os.path.join(archive, name).startswith(utility_dir)] - files = [filename for filename in listing - if filename.startswith(prefix)] + with closing(zipfile.ZipFile(archive)) as fileobj: + listing = [os.path.basename(name) + for name in fileobj.namelist() + if os.path.join(archive, name).startswith(utility_dir)] + files = [filename for filename in listing + if filename.startswith(prefix)] if not files: raise ValueError("No match found for utility code " + util_code_name) if len(files) > 1: @@ -434,16 +434,16 @@ class UtilityCodeBase(object): return code_string def __str__(self): - return "<%s(%s)>" % (type(self).__name__, self.name) + return "<%s(%s)>" % (type(self).__name__, self.name) - def get_tree(self, **kwargs): + def get_tree(self, **kwargs): pass - def __deepcopy__(self, memodict=None): - # No need to deep-copy utility code since it's essentially immutable. - return self + def __deepcopy__(self, memodict=None): + # No need to deep-copy utility code since it's essentially immutable. + return self + - class UtilityCode(UtilityCodeBase): """ Stores utility code to add during code generation. @@ -483,8 +483,8 @@ class UtilityCode(UtilityCodeBase): def __eq__(self, other): if self is other: return True - self_type, other_type = type(self), type(other) - if self_type is not other_type and not (isinstance(other, self_type) or isinstance(self, other_type)): + self_type, other_type = type(self), type(other) + if self_type is not other_type and not (isinstance(other, self_type) or isinstance(self, other_type)): return False self_proto = getattr(self, 'proto', None) @@ -503,7 +503,7 @@ class UtilityCode(UtilityCodeBase): # Dicts aren't hashable... name = self.name if pyrex_type is not None: - data['type'] = pyrex_type.empty_declaration_code() + data['type'] = pyrex_type.empty_declaration_code() data['type_name'] = pyrex_type.specialization_name() name = "%s[%s]" % (name, data['type_name']) key = tuple(sorted(data.items())) @@ -516,11 +516,11 @@ class UtilityCode(UtilityCodeBase): requires = [r.specialize(data) for r in self.requires] s = self._cache[key] = UtilityCode( - 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), - requires, + 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), + requires, self.proto_block, name, ) @@ -532,8 +532,8 @@ class UtilityCode(UtilityCodeBase): """Replace 'PYIDENT("xyz")' by a constant Python identifier cname. """ if 'PYIDENT(' not in impl and 'PYUNICODE(' not in impl: - return False, impl - + return False, impl + replacements = {} def externalise(matchobj): key = matchobj.groups() @@ -549,18 +549,18 @@ class UtilityCode(UtilityCodeBase): assert 'PYIDENT(' not in impl and 'PYUNICODE(' not in impl return True, impl - def inject_unbound_methods(self, impl, output): - """Replace 'UNBOUND_METHOD(type, "name")' by a constant Python identifier cname. - """ - if 'CALL_UNBOUND_METHOD(' not in impl: - return False, impl - - def externalise(matchobj): + def inject_unbound_methods(self, impl, output): + """Replace 'UNBOUND_METHOD(type, "name")' by a constant Python identifier cname. + """ + if 'CALL_UNBOUND_METHOD(' not in impl: + return False, impl + + def externalise(matchobj): type_cname, method_name, obj_cname, args = matchobj.groups() args = [arg.strip() for arg in args[1:].split(',')] if args else [] assert len(args) < 3, "CALL_UNBOUND_METHOD() does not support %d call arguments" % len(args) return output.cached_unbound_method_call_code(obj_cname, type_cname, method_name, args) - + impl = re.sub( r'CALL_UNBOUND_METHOD\(' r'([a-zA-Z_]+),' # type cname @@ -568,46 +568,46 @@ class UtilityCode(UtilityCodeBase): r'\s*([^),]+)' # object cname r'((?:,\s*[^),]+)*)' # args* r'\)', externalise, impl) - assert 'CALL_UNBOUND_METHOD(' not in impl - + assert 'CALL_UNBOUND_METHOD(' not in impl + return True, impl - - def wrap_c_strings(self, impl): - """Replace CSTRING('''xyz''') by a C compatible string - """ - if 'CSTRING(' not in impl: - return impl - - def split_string(matchobj): - content = matchobj.group(1).replace('"', '\042') - return ''.join( - '"%s\\n"\n' % line if not line.endswith('\\') or line.endswith('\\\\') else '"%s"\n' % line[:-1] - for line in content.splitlines()) - - impl = re.sub(r'CSTRING\(\s*"""([^"]*(?:"[^"]+)*)"""\s*\)', split_string, impl) - assert 'CSTRING(' not in impl - return impl - + + def wrap_c_strings(self, impl): + """Replace CSTRING('''xyz''') by a C compatible string + """ + if 'CSTRING(' not in impl: + return impl + + def split_string(matchobj): + content = matchobj.group(1).replace('"', '\042') + return ''.join( + '"%s\\n"\n' % line if not line.endswith('\\') or line.endswith('\\\\') else '"%s"\n' % line[:-1] + for line in content.splitlines()) + + impl = re.sub(r'CSTRING\(\s*"""([^"]*(?:"[^"]+)*)"""\s*\)', split_string, impl) + assert 'CSTRING(' not in impl + return impl + def put_code(self, output): if self.requires: for dependency in self.requires: output.use_utility_code(dependency) if self.proto: - writer = output[self.proto_block] - writer.putln("/* %s.proto */" % self.name) - writer.put_or_include( - self.format_code(self.proto), '%s_proto' % self.name) + writer = output[self.proto_block] + writer.putln("/* %s.proto */" % self.name) + writer.put_or_include( + self.format_code(self.proto), '%s_proto' % self.name) if self.impl: - impl = self.format_code(self.wrap_c_strings(self.impl)) - is_specialised1, impl = self.inject_string_constants(impl, output) - is_specialised2, impl = self.inject_unbound_methods(impl, output) - writer = output['utility_code_def'] - writer.putln("/* %s */" % self.name) - if not (is_specialised1 or is_specialised2): + impl = self.format_code(self.wrap_c_strings(self.impl)) + is_specialised1, impl = self.inject_string_constants(impl, output) + is_specialised2, impl = self.inject_unbound_methods(impl, output) + writer = output['utility_code_def'] + writer.putln("/* %s */" % self.name) + if not (is_specialised1 or is_specialised2): # no module specific adaptations => can be reused - writer.put_or_include(impl, '%s_impl' % self.name) + writer.put_or_include(impl, '%s_impl' % self.name) else: - writer.put(impl) + writer.put(impl) if self.init: writer = output['init_globals'] writer.putln("/* %s.init */" % self.name) @@ -619,7 +619,7 @@ class UtilityCode(UtilityCodeBase): writer.putln() if self.cleanup and Options.generate_cleanup_code: writer = output['cleanup_globals'] - writer.putln("/* %s.cleanup */" % self.name) + writer.putln("/* %s.cleanup */" % self.name) if isinstance(self.cleanup, basestring): writer.put_or_include( self.format_code(self.cleanup), @@ -641,7 +641,7 @@ def sub_tempita(s, context, file=None, name=None): from ..Tempita import sub return sub(s, **context) - + class TempitaUtilityCode(UtilityCode): def __init__(self, name=None, proto=None, impl=None, init=None, file=None, context=None, **kwargs): if context is None: @@ -652,18 +652,18 @@ class TempitaUtilityCode(UtilityCode): super(TempitaUtilityCode, self).__init__( proto, impl, init=init, name=name, file=file, **kwargs) - @classmethod - def load_cached(cls, utility_code_name, from_file=None, context=None, __cache={}): - context_key = tuple(sorted(context.items())) if context else None - assert hash(context_key) is not None # raise TypeError if not hashable - key = (cls, from_file, utility_code_name, context_key) - try: - return __cache[key] - except KeyError: - pass - code = __cache[key] = cls.load(utility_code_name, from_file, context=context) - return code - + @classmethod + def load_cached(cls, utility_code_name, from_file=None, context=None, __cache={}): + context_key = tuple(sorted(context.items())) if context else None + assert hash(context_key) is not None # raise TypeError if not hashable + key = (cls, from_file, utility_code_name, context_key) + try: + return __cache[key] + except KeyError: + pass + code = __cache[key] = cls.load(utility_code_name, from_file, context=context) + return code + def none_or_sub(self, s, context): """ Format a string in this utility code with context. If None, do nothing. @@ -678,7 +678,7 @@ 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'. """ - __name__ = '<lazy>' + __name__ = '<lazy>' requires = None def __init__(self, callback): @@ -699,13 +699,13 @@ class FunctionState(object): # in_try_finally boolean inside try of try...finally # exc_vars (string * 3) exception variables for reraise, or None # can_trace boolean line tracing is supported in the current context - # scope Scope the scope object of the current function + # scope Scope the scope object of the current function # Not used for now, perhaps later - def __init__(self, owner, names_taken=set(), scope=None): + def __init__(self, owner, names_taken=set(), scope=None): self.names_taken = names_taken self.owner = owner - self.scope = scope + self.scope = scope self.error_label = None self.label_counter = 0 @@ -720,7 +720,7 @@ class FunctionState(object): self.exc_vars = None self.current_except = None self.can_trace = False - self.gil_owned = True + self.gil_owned = True self.temps_allocated = [] # of (name, type, manage_ref, static) self.temps_free = {} # (type, manage_ref) -> list of free vars with same type/managed status @@ -846,10 +846,10 @@ class FunctionState(object): A C string referring to the variable is returned. """ - if type.is_const and not type.is_reference: + if type.is_const and not type.is_reference: type = type.const_base_type - elif type.is_reference and not type.is_fake_reference: - type = type.ref_base_type + elif type.is_reference and not type.is_fake_reference: + type = type.ref_base_type elif type.is_cfunction: from . import PyrexTypes type = PyrexTypes.c_ptr_type(type) # A function itself isn't an l-value @@ -860,13 +860,13 @@ class FunctionState(object): freelist = self.temps_free.get((type, manage_ref)) if reusable and freelist is not None and freelist[0]: - result = freelist[0].pop() - freelist[1].remove(result) + result = freelist[0].pop() + freelist[1].remove(result) else: while True: self.temp_counter += 1 result = "%s%d" % (Naming.codewriter_temp_prefix, self.temp_counter) - if result not in self.names_taken: break + if result not in self.names_taken: break self.temps_allocated.append((result, type, manage_ref, static)) if not reusable: self.zombie_temps.add(result) @@ -887,13 +887,13 @@ class FunctionState(object): type, manage_ref = self.temps_used_type[name] freelist = self.temps_free.get((type, manage_ref)) if freelist is None: - freelist = ([], set()) # keep order in list and make lookups in set fast + freelist = ([], set()) # keep order in list and make lookups in set fast self.temps_free[(type, manage_ref)] = freelist - if name in freelist[1]: + if name in freelist[1]: raise RuntimeError("Temp %s freed twice!" % name) if name not in self.zombie_temps: freelist[0].append(name) - freelist[1].add(name) + freelist[1].add(name) if DebugFlags.debug_temp_code_comments: self.owner.putln("/* %s released %s*/" % ( name, " - zombie" if name in self.zombie_temps else "")) @@ -905,7 +905,7 @@ class FunctionState(object): used = [] for name, type, manage_ref, static in self.temps_allocated: freelist = self.temps_free.get((type, manage_ref)) - if freelist is None or name not in freelist[1]: + if freelist is None or name not in freelist[1]: used.append((name, type, manage_ref and type.is_pyobject)) return used @@ -922,8 +922,8 @@ class FunctionState(object): """Return a list of (cname, type) tuples of refcount-managed Python objects. """ return [(cname, type) - for cname, type, manage_ref, static in self.temps_allocated - if manage_ref] + for cname, type, manage_ref, static in self.temps_allocated + if manage_ref] def all_free_managed_temps(self): """Return a list of (cname, type) tuples of refcount-managed Python @@ -931,11 +931,11 @@ class FunctionState(object): try-except and try-finally blocks to clean up temps in the error case. """ - return sorted([ # Enforce deterministic order. - (cname, type) - for (type, manage_ref), freelist in self.temps_free.items() if manage_ref - for cname in freelist[0] - ]) + return sorted([ # Enforce deterministic order. + (cname, type) + for (type, manage_ref), freelist in self.temps_free.items() if manage_ref + for cname in freelist[0] + ]) def start_collecting_temps(self): """ @@ -979,7 +979,7 @@ class PyObjectConst(object): cython.declare(possible_unicode_identifier=object, possible_bytes_identifier=object, replace_identifier=object, find_alphanums=object) -possible_unicode_identifier = re.compile(br"(?![0-9])\w+$".decode('ascii'), re.U).match +possible_unicode_identifier = re.compile(br"(?![0-9])\w+$".decode('ascii'), re.U).match possible_bytes_identifier = re.compile(r"(?![0-9])\w+$".encode('ASCII')).match replace_identifier = re.compile(r'[^a-zA-Z0-9_]+').sub find_alphanums = re.compile('([a-zA-Z0-9]+)').findall @@ -1000,7 +1000,7 @@ class StringConst(object): def add_py_version(self, version): if not version: - self.py_versions = [2, 3] + self.py_versions = [2, 3] elif version not in self.py_versions: self.py_versions.append(version) @@ -1036,9 +1036,9 @@ class StringConst(object): if identifier: intern = True elif identifier is None: - if isinstance(text, bytes): - intern = bool(possible_bytes_identifier(text)) - else: + if isinstance(text, bytes): + intern = bool(possible_bytes_identifier(text)) + else: intern = bool(possible_unicode_identifier(text)) else: intern = False @@ -1129,7 +1129,7 @@ class GlobalState(object): 'typeinfo', 'before_global_var', 'global_var', - 'string_decls', + 'string_decls', 'decls', 'late_includes', 'all_the_rest', @@ -1146,14 +1146,14 @@ class GlobalState(object): ] - def __init__(self, writer, module_node, code_config, common_utility_include_dir=None): + def __init__(self, writer, module_node, code_config, common_utility_include_dir=None): self.filename_table = {} self.filename_list = [] self.input_file_contents = {} self.utility_codes = set() self.declared_cnames = {} self.in_utility_code_generation = False - self.code_config = code_config + self.code_config = code_config self.common_utility_include_dir = common_utility_include_dir self.parts = {} self.module_node = module_node # because some utility code generation needs it @@ -1161,14 +1161,14 @@ class GlobalState(object): self.const_cnames_used = {} self.string_const_index = {} - self.dedup_const_index = {} + self.dedup_const_index = {} self.pyunicode_ptr_const_index = {} self.num_const_index = {} self.py_constants = [] - self.cached_cmethods = {} - self.initialised_constants = set() + self.cached_cmethods = {} + self.initialised_constants = set() - writer.set_global_state(self) + writer.set_global_state(self) self.rootwriter = writer def initialize_main_c_code(self): @@ -1181,19 +1181,19 @@ class GlobalState(object): else: w = self.parts['cached_builtins'] w.enter_cfunc_scope() - w.putln("static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) {") + w.putln("static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) {") w = self.parts['cached_constants'] w.enter_cfunc_scope() w.putln("") - w.putln("static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) {") + w.putln("static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) {") w.put_declare_refcount_context() w.put_setup_refcount_context("__Pyx_InitCachedConstants") w = self.parts['init_globals'] w.enter_cfunc_scope() w.putln("") - w.putln("static CYTHON_SMALL_CODE int __Pyx_InitGlobals(void) {") + w.putln("static CYTHON_SMALL_CODE int __Pyx_InitGlobals(void) {") if not Options.generate_cleanup_code: del self.parts['cleanup_globals'] @@ -1201,17 +1201,17 @@ class GlobalState(object): w = self.parts['cleanup_globals'] w.enter_cfunc_scope() w.putln("") - w.putln("static CYTHON_SMALL_CODE void __Pyx_CleanupGlobals(void) {") + w.putln("static CYTHON_SMALL_CODE void __Pyx_CleanupGlobals(void) {") + + code = self.parts['utility_code_proto'] + code.putln("") + code.putln("/* --- Runtime support code (head) --- */") - code = self.parts['utility_code_proto'] - code.putln("") - code.putln("/* --- Runtime support code (head) --- */") - code = self.parts['utility_code_def'] - if self.code_config.emit_linenums: + if self.code_config.emit_linenums: code.write('\n#line 1 "cython_utility"\n') code.putln("") - code.putln("/* --- Runtime support code --- */") + code.putln("/* --- Runtime support code --- */") def finalize_main_c_code(self): self.close_global_decls() @@ -1220,8 +1220,8 @@ class GlobalState(object): # utility_code_def # code = self.parts['utility_code_def'] - util = TempitaUtilityCode.load_cached("TypeConversions", "TypeConversion.c") - code.put(util.format_code(util.impl)) + util = TempitaUtilityCode.load_cached("TypeConversions", "TypeConversion.c") + code.put(util.format_code(util.impl)) code.putln("") def __getitem__(self, key): @@ -1276,12 +1276,12 @@ class GlobalState(object): # constant handling at code generation time - def get_cached_constants_writer(self, target=None): - if target is not None: - if target in self.initialised_constants: - # Return None on second/later calls to prevent duplicate creation code. - return None - self.initialised_constants.add(target) + def get_cached_constants_writer(self, target=None): + if target is not None: + if target in self.initialised_constants: + # Return None on second/later calls to prevent duplicate creation code. + return None + self.initialised_constants.add(target) return self.parts['cached_constants'] def get_int_const(self, str_value, longness=False): @@ -1299,19 +1299,19 @@ class GlobalState(object): c = self.new_num_const(str_value, 'float', value_code) return c - def get_py_const(self, type, prefix='', cleanup_level=None, dedup_key=None): - if dedup_key is not None: - const = self.dedup_const_index.get(dedup_key) - if const is not None: - return const + def get_py_const(self, type, prefix='', cleanup_level=None, dedup_key=None): + if dedup_key is not None: + const = self.dedup_const_index.get(dedup_key) + if const is not None: + return const # create a new Python object constant const = self.new_py_const(type, prefix) if cleanup_level is not None \ and cleanup_level <= Options.generate_cleanup_code: cleanup_writer = self.parts['cleanup_globals'] cleanup_writer.putln('Py_CLEAR(%s);' % const.cname) - if dedup_key is not None: - self.dedup_const_index[dedup_key] = const + if dedup_key is not None: + self.dedup_const_index[dedup_key] = const return const def get_string_const(self, text, py_version=None): @@ -1401,13 +1401,13 @@ class GlobalState(object): def get_cached_unbound_method(self, type_cname, method_name): key = (type_cname, method_name) - try: - cname = self.cached_cmethods[key] - except KeyError: - cname = self.cached_cmethods[key] = self.new_const_cname( - 'umethod', '%s_%s' % (type_cname, method_name)) - return cname - + try: + cname = self.cached_cmethods[key] + except KeyError: + cname = self.cached_cmethods[key] = self.new_const_cname( + 'umethod', '%s_%s' % (type_cname, method_name)) + return cname + def cached_unbound_method_call_code(self, obj_cname, type_cname, method_name, arg_cnames): # admittedly, not the best place to put this method, but it is reused by UtilityCode and ExprNodes ... utility_code_name = "CallUnboundCMethod%d" % len(arg_cnames) @@ -1451,54 +1451,54 @@ class GlobalState(object): w.error_goto(pos))) def generate_const_declarations(self): - self.generate_cached_methods_decls() + self.generate_cached_methods_decls() self.generate_string_constants() self.generate_num_constants() 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 = [(len(c.cname), c.cname, c) + for c in self.py_constants] consts.sort() decls_writer = self.parts['decls'] for _, cname, c in consts: decls_writer.putln( "static %s;" % c.type.declaration_code(cname)) - def generate_cached_methods_decls(self): - if not self.cached_cmethods: - return - - decl = self.parts['decls'] - init = self.parts['init_globals'] - cnames = [] + def generate_cached_methods_decls(self): + if not self.cached_cmethods: + return + + decl = self.parts['decls'] + init = self.parts['init_globals'] + cnames = [] for (type_cname, method_name), cname in sorted(self.cached_cmethods.items()): - cnames.append(cname) - method_name_cname = self.get_interned_identifier(StringEncoding.EncodedString(method_name)).cname - decl.putln('static __Pyx_CachedCFunction %s = {0, &%s, 0, 0, 0};' % ( - cname, method_name_cname)) - # split type reference storage as it might not be static - init.putln('%s.type = (PyObject*)&%s;' % ( - cname, type_cname)) - - if Options.generate_cleanup_code: - cleanup = self.parts['cleanup_globals'] - for cname in cnames: - cleanup.putln("Py_CLEAR(%s.method);" % cname) - + cnames.append(cname) + method_name_cname = self.get_interned_identifier(StringEncoding.EncodedString(method_name)).cname + decl.putln('static __Pyx_CachedCFunction %s = {0, &%s, 0, 0, 0};' % ( + cname, method_name_cname)) + # split type reference storage as it might not be static + init.putln('%s.type = (PyObject*)&%s;' % ( + cname, type_cname)) + + if Options.generate_cleanup_code: + cleanup = self.parts['cleanup_globals'] + for cname in cnames: + cleanup.putln("Py_CLEAR(%s.method);" % cname) + def generate_string_constants(self): - c_consts = [(len(c.cname), c.cname, c) for c in self.string_const_index.values()] + c_consts = [(len(c.cname), c.cname, c) for c in self.string_const_index.values()] c_consts.sort() py_strings = [] - decls_writer = self.parts['string_decls'] + decls_writer = self.parts['string_decls'] for _, cname, c in c_consts: 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 '>=')) - decls_writer.putln('static const char %s[] = "%s";' % ( + decls_writer.putln('static const char %s[] = "%s";' % ( cname, StringEncoding.split_string_literal(c.escaped_value))) if conditional: decls_writer.putln("#endif") @@ -1506,7 +1506,7 @@ class GlobalState(object): for py_string in c.py_strings.values(): py_strings.append((c.cname, len(py_string.cname), py_string)) - for c, cname in sorted(self.pyunicode_ptr_const_index.items()): + for c, cname in sorted(self.pyunicode_ptr_const_index.items()): utf16_array, utf32_array = StringEncoding.encode_pyunicode_string(c) if utf16_array: # Narrow and wide representations differ @@ -1522,11 +1522,11 @@ class GlobalState(object): py_strings.sort() w = self.parts['pystring_table'] w.putln("") - w.putln("static __Pyx_StringTabEntry %s[] = {" % Naming.stringtab_cname) + w.putln("static __Pyx_StringTabEntry %s[] = {" % Naming.stringtab_cname) for c_cname, _, py_string in py_strings: if not py_string.is_str or not py_string.encoding or \ - py_string.encoding in ('ASCII', 'USASCII', 'US-ASCII', - 'UTF8', 'UTF-8'): + py_string.encoding in ('ASCII', 'USASCII', 'US-ASCII', + 'UTF8', 'UTF-8'): encoding = '0' else: encoding = '"%s"' % py_string.encoding.lower() @@ -1535,7 +1535,7 @@ class GlobalState(object): "static PyObject *%s;" % py_string.cname) if py_string.py3str_cstring: w.putln("#if PY_MAJOR_VERSION >= 3") - w.putln("{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % ( + w.putln("{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % ( py_string.cname, py_string.py3str_cstring.cname, py_string.py3str_cstring.cname, @@ -1543,7 +1543,7 @@ class GlobalState(object): py_string.intern )) w.putln("#else") - w.putln("{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % ( + w.putln("{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % ( py_string.cname, c_cname, c_cname, @@ -1605,13 +1605,13 @@ class GlobalState(object): # File name state # - def lookup_filename(self, source_desc): + def lookup_filename(self, source_desc): entry = source_desc.get_filenametable_entry() try: index = self.filename_table[entry] except KeyError: index = len(self.filename_list) - self.filename_list.append(source_desc) + self.filename_list.append(source_desc) self.filename_table[entry] = index return index @@ -1649,21 +1649,21 @@ class GlobalState(object): See UtilityCode. """ - if utility_code and utility_code not in self.utility_codes: + if utility_code and utility_code not in self.utility_codes: self.utility_codes.add(utility_code) utility_code.put_code(self) - def use_entry_utility_code(self, entry): - if entry is None: - return - if entry.utility_code: - self.use_utility_code(entry.utility_code) - if entry.utility_code_definition: - self.use_utility_code(entry.utility_code_definition) - - -def funccontext_property(func): - name = func.__name__ + def use_entry_utility_code(self, entry): + if entry is None: + return + if entry.utility_code: + self.use_utility_code(entry.utility_code) + if entry.utility_code_definition: + self.use_utility_code(entry.utility_code_definition) + + +def funccontext_property(func): + name = func.__name__ attribute_of = operator.attrgetter(name) def get(self): return attribute_of(self.funcstate) @@ -1672,17 +1672,17 @@ def funccontext_property(func): return property(get, set) -class CCodeConfig(object): - # emit_linenums boolean write #line pragmas? - # emit_code_comments boolean copy the original code into C comments? - # c_line_in_traceback boolean append the c file and line number to the traceback for exceptions? - - def __init__(self, emit_linenums=True, emit_code_comments=True, c_line_in_traceback=True): - self.emit_code_comments = emit_code_comments - self.emit_linenums = emit_linenums - self.c_line_in_traceback = c_line_in_traceback - - +class CCodeConfig(object): + # emit_linenums boolean write #line pragmas? + # emit_code_comments boolean copy the original code into C comments? + # c_line_in_traceback boolean append the c file and line number to the traceback for exceptions? + + def __init__(self, emit_linenums=True, emit_code_comments=True, c_line_in_traceback=True): + self.emit_code_comments = emit_code_comments + self.emit_linenums = emit_linenums + self.c_line_in_traceback = c_line_in_traceback + + class CCodeWriter(object): """ Utility class to output C code. @@ -1712,46 +1712,46 @@ class CCodeWriter(object): # utility code, declared constants etc.) # pyclass_stack list used during recursive code generation to pass information # about the current class one is in - # code_config CCodeConfig configuration options for the C code writer + # code_config CCodeConfig configuration options for the C code writer - @cython.locals(create_from='CCodeWriter') - def __init__(self, create_from=None, buffer=None, copy_formatting=False): + @cython.locals(create_from='CCodeWriter') + def __init__(self, create_from=None, buffer=None, copy_formatting=False): if buffer is None: buffer = StringIOTree() self.buffer = buffer - self.last_pos = None - self.last_marked_pos = None + self.last_pos = None + self.last_marked_pos = None self.pyclass_stack = [] self.funcstate = None - self.globalstate = None - self.code_config = None + self.globalstate = None + self.code_config = None self.level = 0 self.call_level = 0 self.bol = 1 if create_from is not None: # Use same global state - self.set_global_state(create_from.globalstate) + self.set_global_state(create_from.globalstate) self.funcstate = create_from.funcstate # Clone formatting state if copy_formatting: self.level = create_from.level self.bol = create_from.bol self.call_level = create_from.call_level - self.last_pos = create_from.last_pos - self.last_marked_pos = create_from.last_marked_pos + self.last_pos = create_from.last_pos + self.last_marked_pos = create_from.last_marked_pos def create_new(self, create_from, buffer, copy_formatting): # polymorphic constructor -- very slightly more versatile # than using __class__ - result = CCodeWriter(create_from, buffer, copy_formatting) + result = CCodeWriter(create_from, buffer, copy_formatting) return result - def set_global_state(self, global_state): - assert self.globalstate is None # prevent overwriting once it's set - self.globalstate = global_state - self.code_config = global_state.code_config - + def set_global_state(self, global_state): + assert self.globalstate is None # prevent overwriting once it's set + self.globalstate = global_state + self.code_config = global_state.code_config + def copyto(self, f): self.buffer.copyto(f) @@ -1761,7 +1761,7 @@ class CCodeWriter(object): def write(self, s): # also put invalid markers (lineno 0), to indicate that those lines # have no Cython source code correspondence - cython_lineno = self.last_marked_pos[1] if self.last_marked_pos else 0 + cython_lineno = self.last_marked_pos[1] if self.last_marked_pos else 0 self.buffer.markers.extend([cython_lineno] * s.count('\n')) self.buffer.write(s) @@ -1774,7 +1774,7 @@ class CCodeWriter(object): Creates a new CCodeWriter connected to the same global state, which can later be inserted using insert. """ - return CCodeWriter(create_from=self) + return CCodeWriter(create_from=self) def insert(self, writer): """ @@ -1787,22 +1787,22 @@ class CCodeWriter(object): self.buffer.insert(writer.buffer) # Properties delegated to function scope - @funccontext_property - def label_counter(self): pass - @funccontext_property - def return_label(self): pass - @funccontext_property - def error_label(self): pass - @funccontext_property - def labels_used(self): pass - @funccontext_property - def continue_label(self): pass - @funccontext_property - def break_label(self): pass - @funccontext_property - def return_from_error_cleanup_label(self): pass - @funccontext_property - def yield_labels(self): pass + @funccontext_property + def label_counter(self): pass + @funccontext_property + def return_label(self): pass + @funccontext_property + def error_label(self): pass + @funccontext_property + def labels_used(self): pass + @funccontext_property + def continue_label(self): pass + @funccontext_property + def break_label(self): pass + @funccontext_property + def return_from_error_cleanup_label(self): pass + @funccontext_property + def yield_labels(self): pass # Functions delegated to function scope def new_label(self, name=None): return self.funcstate.new_label(name) @@ -1818,8 +1818,8 @@ class CCodeWriter(object): def label_used(self, lbl): return self.funcstate.label_used(lbl) - def enter_cfunc_scope(self, scope=None): - self.funcstate = FunctionState(self, scope=scope) + def enter_cfunc_scope(self, scope=None): + self.funcstate = FunctionState(self, scope=scope) def exit_cfunc_scope(self): self.funcstate = None @@ -1832,8 +1832,8 @@ class CCodeWriter(object): def get_py_float(self, str_value, value_code): return self.globalstate.get_float_const(str_value, value_code).cname - def get_py_const(self, type, prefix='', cleanup_level=None, dedup_key=None): - return self.globalstate.get_py_const(type, prefix, cleanup_level, dedup_key).cname + def get_py_const(self, type, prefix='', cleanup_level=None, dedup_key=None): + return self.globalstate.get_py_const(type, prefix, cleanup_level, dedup_key).cname def get_string_const(self, text): return self.globalstate.get_string_const(text).cname @@ -1855,17 +1855,17 @@ class CCodeWriter(object): def intern_identifier(self, text): return self.get_py_string_const(text, identifier=True) - def get_cached_constants_writer(self, target=None): - return self.globalstate.get_cached_constants_writer(target) + def get_cached_constants_writer(self, target=None): + return self.globalstate.get_cached_constants_writer(target) # code generation def putln(self, code="", safe=False): - if self.last_pos and self.bol: + if self.last_pos and self.bol: self.emit_marker() - if self.code_config.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())) + if self.code_config.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())) if code: if safe: self.put_safe(code) @@ -1874,35 +1874,35 @@ class CCodeWriter(object): self.write("\n") self.bol = 1 - def mark_pos(self, pos, trace=True): - if pos is None: - return - if self.last_marked_pos and self.last_marked_pos[:2] == pos[:2]: - return - self.last_pos = (pos, trace) - + def mark_pos(self, pos, trace=True): + if pos is None: + return + if self.last_marked_pos and self.last_marked_pos[:2] == pos[:2]: + return + self.last_pos = (pos, trace) + def emit_marker(self): - pos, trace = self.last_pos - self.last_marked_pos = pos - self.last_pos = None + pos, trace = self.last_pos + self.last_marked_pos = pos + self.last_pos = None self.write("\n") - if self.code_config.emit_code_comments: - self.indent() - self.write("/* %s */\n" % self._build_marker(pos)) - if trace and self.funcstate and self.funcstate.can_trace and self.globalstate.directives['linetrace']: + if self.code_config.emit_code_comments: + self.indent() + self.write("/* %s */\n" % self._build_marker(pos)) + if trace and self.funcstate and self.funcstate.can_trace and self.globalstate.directives['linetrace']: self.indent() - 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)) - + 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)) + def put_safe(self, code): # put code, but ignore {} self.write(code) @@ -1916,7 +1916,7 @@ class CCodeWriter(object): path = os.path.join(include_dir, include_file) if not os.path.exists(path): tmp_path = '%s.tmp%s' % (path, os.getpid()) - with closing(Utils.open_new_file(tmp_path)) as f: + with closing(Utils.open_new_file(tmp_path)) as f: f.write(code) shutil.move(tmp_path, path) code = '#include "%s"\n' % path @@ -2023,10 +2023,10 @@ class CCodeWriter(object): self.putln("%sconst char *%s = NULL;" % (unused, Naming.filename_cname)) self.putln("%sint %s = 0;" % (unused, Naming.clineno_cname)) - def put_generated_by(self): - self.putln("/* Generated by Cython %s */" % Version.watermark) - self.putln("") - + def put_generated_by(self): + self.putln("/* Generated by Cython %s */" % Version.watermark) + self.putln("") + def put_h_guard(self, guard): self.putln("#ifndef %s" % guard) self.putln("#define %s" % guard) @@ -2100,10 +2100,10 @@ class CCodeWriter(object): else: self.putln("Py_INCREF(%s);" % self.entry_as_pyobject(entry)) - def put_var_xincref(self, entry): - if entry.type.is_pyobject: - self.putln("__Pyx_XINCREF(%s);" % self.entry_as_pyobject(entry)) - + def put_var_xincref(self, entry): + if entry.type.is_pyobject: + self.putln("__Pyx_XINCREF(%s);" % self.entry_as_pyobject(entry)) + 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) @@ -2219,9 +2219,9 @@ class CCodeWriter(object): if entry.in_closure: self.put_giveref('Py_None') - def put_pymethoddef(self, entry, term, allow_skip=True, wrapper_code_writer=None): + def put_pymethoddef(self, entry, term, allow_skip=True, wrapper_code_writer=None): if entry.is_special or entry.name == '__getattribute__': - if entry.name not in special_py_methods: + if entry.name not in special_py_methods: if entry.name == '__getattr__' and not self.globalstate.directives['fast_getattr']: pass # Python's typeobject.c will automatically fill in our slot @@ -2229,39 +2229,39 @@ class CCodeWriter(object): # that's better than ours. elif allow_skip: return - + method_flags = entry.signature.method_flags() - if not method_flags: - return - if entry.is_special: - from . import TypeSlots - method_flags += [TypeSlots.method_coexist] - func_ptr = wrapper_code_writer.put_pymethoddef_wrapper(entry) if wrapper_code_writer else entry.func_cname - # Add required casts, but try not to shadow real warnings. - cast = '__Pyx_PyCFunctionFast' if 'METH_FASTCALL' in method_flags else 'PyCFunction' - if 'METH_KEYWORDS' in method_flags: - cast += 'WithKeywords' - if cast != 'PyCFunction': - func_ptr = '(void*)(%s)%s' % (cast, func_ptr) - self.putln( - '{"%s", (PyCFunction)%s, %s, %s}%s' % ( - entry.name, - func_ptr, - "|".join(method_flags), - entry.doc_cname if entry.doc else '0', - term)) - - def put_pymethoddef_wrapper(self, entry): - func_cname = entry.func_cname - if entry.is_special: - method_flags = entry.signature.method_flags() - if method_flags and 'METH_NOARGS' in method_flags: - # Special NOARGS methods really take no arguments besides 'self', but PyCFunction expects one. - func_cname = Naming.method_wrapper_prefix + func_cname - self.putln("static PyObject *%s(PyObject *self, CYTHON_UNUSED PyObject *arg) {return %s(self);}" % ( - func_cname, entry.func_cname)) - return func_cname - + if not method_flags: + return + if entry.is_special: + from . import TypeSlots + method_flags += [TypeSlots.method_coexist] + func_ptr = wrapper_code_writer.put_pymethoddef_wrapper(entry) if wrapper_code_writer else entry.func_cname + # Add required casts, but try not to shadow real warnings. + cast = '__Pyx_PyCFunctionFast' if 'METH_FASTCALL' in method_flags else 'PyCFunction' + if 'METH_KEYWORDS' in method_flags: + cast += 'WithKeywords' + if cast != 'PyCFunction': + func_ptr = '(void*)(%s)%s' % (cast, func_ptr) + self.putln( + '{"%s", (PyCFunction)%s, %s, %s}%s' % ( + entry.name, + func_ptr, + "|".join(method_flags), + entry.doc_cname if entry.doc else '0', + term)) + + def put_pymethoddef_wrapper(self, entry): + func_cname = entry.func_cname + if entry.is_special: + method_flags = entry.signature.method_flags() + if method_flags and 'METH_NOARGS' in method_flags: + # Special NOARGS methods really take no arguments besides 'self', but PyCFunction expects one. + func_cname = Naming.method_wrapper_prefix + func_cname + self.putln("static PyObject *%s(PyObject *self, CYTHON_UNUSED PyObject *arg) {return %s(self);}" % ( + func_cname, entry.func_cname)) + return func_cname + # GIL methods def put_ensure_gil(self, declare_gilstate=True, variable=None): @@ -2337,8 +2337,8 @@ class CCodeWriter(object): # error handling def put_error_if_neg(self, pos, value): - # TODO this path is almost _never_ taken, yet this macro makes is slower! - # 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 (unlikely(%s < 0)) %s" % (value, self.error_goto(pos))) return self.putln("if (%s < 0) %s" % (value, self.error_goto(pos))) def put_error_if_unbound(self, pos, entry, in_nogil_context=False): @@ -2373,14 +2373,14 @@ class CCodeWriter(object): def error_goto(self, pos, used=True): lbl = self.funcstate.error_label self.funcstate.use_label(lbl) - if pos is None: - return 'goto %s;' % lbl + if pos is None: + return 'goto %s;' % lbl self.funcstate.should_declare_error_indicator = True if used: self.funcstate.uses_error_indicator = True - return "__PYX_ERR(%s, %s, %s)" % ( - self.lookup_filename(pos[0]), - pos[1], + return "__PYX_ERR(%s, %s, %s)" % ( + self.lookup_filename(pos[0]), + pos[1], lbl) def error_goto_if(self, cond, pos): @@ -2425,7 +2425,7 @@ class CCodeWriter(object): self.funcstate.uses_error_indicator = True self.putln('__Pyx_AddTraceback("%s", %s, %s, %s);' % format_tuple) - def put_unraisable(self, qualified_name, nogil=False): + def put_unraisable(self, qualified_name, nogil=False): """ Generate code to print a Python warning for an unraisable exception. @@ -2436,30 +2436,30 @@ class CCodeWriter(object): Naming.clineno_cname, Naming.lineno_cname, Naming.filename_cname, - self.globalstate.directives['unraisable_tracebacks'], - nogil, + self.globalstate.directives['unraisable_tracebacks'], + nogil, ) self.funcstate.uses_error_indicator = True - self.putln('__Pyx_WriteUnraisable("%s", %s, %s, %s, %d, %d);' % format_tuple) + self.putln('__Pyx_WriteUnraisable("%s", %s, %s, %s, %d, %d);' % format_tuple) self.globalstate.use_utility_code( UtilityCode.load_cached("WriteUnraisableException", "Exceptions.c")) def put_trace_declarations(self): self.putln('__Pyx_TraceDeclarations') - def put_trace_frame_init(self, codeobj=None): - if codeobj: - self.putln('__Pyx_TraceFrameInit(%s)' % codeobj) + def put_trace_frame_init(self, codeobj=None): + if codeobj: + self.putln('__Pyx_TraceFrameInit(%s)' % codeobj) + + def put_trace_call(self, name, pos, nogil=False): + 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))) - def put_trace_call(self, name, pos, nogil=False): - 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))) - def put_trace_exception(self): self.putln("__Pyx_TraceException();") - def put_trace_return(self, retvalue_cname, nogil=False): - self.putln("__Pyx_TraceReturn(%s, %d);" % (retvalue_cname, nogil)) + def put_trace_return(self, retvalue_cname, nogil=False): + self.putln("__Pyx_TraceReturn(%s, %d);" % (retvalue_cname, nogil)) def putln_openmp(self, string): self.putln("#ifdef _OPENMP") @@ -2543,7 +2543,7 @@ class PyxCodeWriter(object): def getvalue(self): result = self.buffer.getvalue() - if isinstance(result, bytes): + if isinstance(result, bytes): result = result.decode(self.encoding) return result @@ -2585,7 +2585,7 @@ class ClosureTempAllocator(object): self.temps_free[type] = list(cnames) def allocate_temp(self, type): - if type not in self.temps_allocated: + if type not in self.temps_allocated: self.temps_allocated[type] = [] self.temps_free[type] = [] elif self.temps_free[type]: diff --git a/contrib/tools/cython/Cython/Compiler/CythonScope.py b/contrib/tools/cython/Cython/Compiler/CythonScope.py index 70e83916b5..1c25d1a6b4 100644 --- a/contrib/tools/cython/Cython/Compiler/CythonScope.py +++ b/contrib/tools/cython/Cython/Compiler/CythonScope.py @@ -71,9 +71,9 @@ class CythonScope(ModuleScope): name_path = qname.split(u'.') scope = self while len(name_path) > 1: - scope = scope.lookup_here(name_path[0]) - if scope: - scope = scope.as_module + scope = scope.lookup_here(name_path[0]) + if scope: + scope = scope.as_module del name_path[0] if scope is None: return None diff --git a/contrib/tools/cython/Cython/Compiler/Errors.py b/contrib/tools/cython/Cython/Compiler/Errors.py index aa7a40437c..9761b52c32 100644 --- a/contrib/tools/cython/Cython/Compiler/Errors.py +++ b/contrib/tools/cython/Cython/Compiler/Errors.py @@ -4,11 +4,11 @@ from __future__ import absolute_import -try: - from __builtin__ import basestring as any_string_type -except ImportError: - any_string_type = (bytes, str) - +try: + from __builtin__ import basestring as any_string_type +except ImportError: + any_string_type = (bytes, str) + import sys from contextlib import contextmanager @@ -27,7 +27,7 @@ class PyrexWarning(Exception): def context(position): source = position[0] - assert not (isinstance(source, any_string_type)), ( + assert not (isinstance(source, any_string_type)), ( "Please replace filename strings with Scanning.FileSourceDescriptor instances %r" % source) try: F = source.get_lines() @@ -173,7 +173,7 @@ def report_error(err, use_stack=True): def error(position, message): - #print("Errors.error:", repr(position), repr(message)) ### + #print("Errors.error:", repr(position), repr(message)) ### if position is None: raise InternalError(message) err = CompileError(position, message) diff --git a/contrib/tools/cython/Cython/Compiler/ExprNodes.py b/contrib/tools/cython/Cython/Compiler/ExprNodes.py index 45938521c9..4a402f8126 100644 --- a/contrib/tools/cython/Cython/Compiler/ExprNodes.py +++ b/contrib/tools/cython/Cython/Compiler/ExprNodes.py @@ -13,12 +13,12 @@ cython.declare(error=object, warning=object, warn_once=object, InternalError=obj unicode_type=object, str_type=object, bytes_type=object, type_type=object, Builtin=object, Symtab=object, Utils=object, find_coercion_error=object, debug_disposal_code=object, debug_temp_alloc=object, debug_coercion=object, - bytearray_type=object, slice_type=object, _py_int_types=object, - IS_PYTHON3=cython.bint) + bytearray_type=object, slice_type=object, _py_int_types=object, + IS_PYTHON3=cython.bint) import re -import sys -import copy +import sys +import copy import os.path import operator @@ -43,31 +43,31 @@ from . import Future from ..Debugging import print_call_chain from .DebugFlags import debug_disposal_code, debug_temp_alloc, \ debug_coercion -from .Pythran import (to_pythran, is_pythran_supported_type, is_pythran_supported_operation_type, - is_pythran_expr, pythran_func_type, pythran_binop_type, pythran_unaryop_type, has_np_pythran, - pythran_indexing_code, pythran_indexing_type, is_pythran_supported_node_or_none, pythran_type, - pythran_is_numpy_func_supported, pythran_get_func_include_file, pythran_functor) +from .Pythran import (to_pythran, is_pythran_supported_type, is_pythran_supported_operation_type, + is_pythran_expr, pythran_func_type, pythran_binop_type, pythran_unaryop_type, has_np_pythran, + pythran_indexing_code, pythran_indexing_type, is_pythran_supported_node_or_none, pythran_type, + pythran_is_numpy_func_supported, pythran_get_func_include_file, pythran_functor) from .PyrexTypes import PythranExpr try: from __builtin__ import basestring except ImportError: - # Python 3 - basestring = str - any_string_type = (bytes, str) -else: - # Python 2 - any_string_type = (bytes, unicode) - - -if sys.version_info[0] >= 3: - IS_PYTHON3 = True - _py_int_types = int -else: - IS_PYTHON3 = False - _py_int_types = (int, long) - - + # Python 3 + basestring = str + any_string_type = (bytes, str) +else: + # Python 2 + any_string_type = (bytes, unicode) + + +if sys.version_info[0] >= 3: + IS_PYTHON3 = True + _py_int_types = int +else: + IS_PYTHON3 = False + _py_int_types = (int, long) + + class NotConstant(object): _obj = None @@ -86,46 +86,46 @@ constant_value_not_set = object() # error messages when coercing from key[0] to key[1] coercion_error_dict = { # string related errors - (unicode_type, str_type): ("Cannot convert Unicode string to 'str' implicitly." - " This is not portable and requires explicit encoding."), - (unicode_type, bytes_type): "Cannot convert Unicode string to 'bytes' implicitly, encoding required.", - (unicode_type, PyrexTypes.c_char_ptr_type): "Unicode objects only support coercion to Py_UNICODE*.", - (unicode_type, PyrexTypes.c_const_char_ptr_type): "Unicode objects only support coercion to Py_UNICODE*.", - (unicode_type, PyrexTypes.c_uchar_ptr_type): "Unicode objects only support coercion to Py_UNICODE*.", - (unicode_type, PyrexTypes.c_const_uchar_ptr_type): "Unicode objects only support coercion to Py_UNICODE*.", - (bytes_type, unicode_type): "Cannot convert 'bytes' object to unicode implicitly, decoding required", - (bytes_type, str_type): "Cannot convert 'bytes' object to str implicitly. This is not portable to Py3.", - (bytes_type, basestring_type): ("Cannot convert 'bytes' object to basestring implicitly." - " This is not portable to Py3."), - (bytes_type, PyrexTypes.c_py_unicode_ptr_type): "Cannot convert 'bytes' object to Py_UNICODE*, use 'unicode'.", - (bytes_type, PyrexTypes.c_const_py_unicode_ptr_type): ( - "Cannot convert 'bytes' object to Py_UNICODE*, use 'unicode'."), - (basestring_type, bytes_type): "Cannot convert 'basestring' object to bytes implicitly. This is not portable.", - (str_type, unicode_type): ("str objects do not support coercion to unicode," - " use a unicode string literal instead (u'')"), - (str_type, bytes_type): "Cannot convert 'str' to 'bytes' implicitly. This is not portable.", - (str_type, PyrexTypes.c_char_ptr_type): "'str' objects do not support coercion to C types (use 'bytes'?).", - (str_type, PyrexTypes.c_const_char_ptr_type): "'str' objects do not support coercion to C types (use 'bytes'?).", - (str_type, PyrexTypes.c_uchar_ptr_type): "'str' objects do not support coercion to C types (use 'bytes'?).", - (str_type, PyrexTypes.c_const_uchar_ptr_type): "'str' objects do not support coercion to C types (use 'bytes'?).", - (str_type, PyrexTypes.c_py_unicode_ptr_type): "'str' objects do not support coercion to C types (use 'unicode'?).", - (str_type, PyrexTypes.c_const_py_unicode_ptr_type): ( - "'str' objects do not support coercion to C types (use 'unicode'?)."), - (PyrexTypes.c_char_ptr_type, unicode_type): "Cannot convert 'char*' to unicode implicitly, decoding required", - (PyrexTypes.c_const_char_ptr_type, unicode_type): ( - "Cannot convert 'char*' to unicode implicitly, decoding required"), - (PyrexTypes.c_uchar_ptr_type, unicode_type): "Cannot convert 'char*' to unicode implicitly, decoding required", - (PyrexTypes.c_const_uchar_ptr_type, unicode_type): ( - "Cannot convert 'char*' to unicode implicitly, decoding required"), + (unicode_type, str_type): ("Cannot convert Unicode string to 'str' implicitly." + " This is not portable and requires explicit encoding."), + (unicode_type, bytes_type): "Cannot convert Unicode string to 'bytes' implicitly, encoding required.", + (unicode_type, PyrexTypes.c_char_ptr_type): "Unicode objects only support coercion to Py_UNICODE*.", + (unicode_type, PyrexTypes.c_const_char_ptr_type): "Unicode objects only support coercion to Py_UNICODE*.", + (unicode_type, PyrexTypes.c_uchar_ptr_type): "Unicode objects only support coercion to Py_UNICODE*.", + (unicode_type, PyrexTypes.c_const_uchar_ptr_type): "Unicode objects only support coercion to Py_UNICODE*.", + (bytes_type, unicode_type): "Cannot convert 'bytes' object to unicode implicitly, decoding required", + (bytes_type, str_type): "Cannot convert 'bytes' object to str implicitly. This is not portable to Py3.", + (bytes_type, basestring_type): ("Cannot convert 'bytes' object to basestring implicitly." + " This is not portable to Py3."), + (bytes_type, PyrexTypes.c_py_unicode_ptr_type): "Cannot convert 'bytes' object to Py_UNICODE*, use 'unicode'.", + (bytes_type, PyrexTypes.c_const_py_unicode_ptr_type): ( + "Cannot convert 'bytes' object to Py_UNICODE*, use 'unicode'."), + (basestring_type, bytes_type): "Cannot convert 'basestring' object to bytes implicitly. This is not portable.", + (str_type, unicode_type): ("str objects do not support coercion to unicode," + " use a unicode string literal instead (u'')"), + (str_type, bytes_type): "Cannot convert 'str' to 'bytes' implicitly. This is not portable.", + (str_type, PyrexTypes.c_char_ptr_type): "'str' objects do not support coercion to C types (use 'bytes'?).", + (str_type, PyrexTypes.c_const_char_ptr_type): "'str' objects do not support coercion to C types (use 'bytes'?).", + (str_type, PyrexTypes.c_uchar_ptr_type): "'str' objects do not support coercion to C types (use 'bytes'?).", + (str_type, PyrexTypes.c_const_uchar_ptr_type): "'str' objects do not support coercion to C types (use 'bytes'?).", + (str_type, PyrexTypes.c_py_unicode_ptr_type): "'str' objects do not support coercion to C types (use 'unicode'?).", + (str_type, PyrexTypes.c_const_py_unicode_ptr_type): ( + "'str' objects do not support coercion to C types (use 'unicode'?)."), + (PyrexTypes.c_char_ptr_type, unicode_type): "Cannot convert 'char*' to unicode implicitly, decoding required", + (PyrexTypes.c_const_char_ptr_type, unicode_type): ( + "Cannot convert 'char*' to unicode implicitly, decoding required"), + (PyrexTypes.c_uchar_ptr_type, unicode_type): "Cannot convert 'char*' to unicode implicitly, decoding required", + (PyrexTypes.c_const_uchar_ptr_type, unicode_type): ( + "Cannot convert 'char*' to unicode implicitly, decoding required"), } def find_coercion_error(type_tuple, default, env): err = coercion_error_dict.get(type_tuple) if err is None: return default - elif (env.directives['c_string_encoding'] and - any(t in type_tuple for t in (PyrexTypes.c_char_ptr_type, PyrexTypes.c_uchar_ptr_type, - PyrexTypes.c_const_char_ptr_type, PyrexTypes.c_const_uchar_ptr_type))): + elif (env.directives['c_string_encoding'] and + any(t in type_tuple for t in (PyrexTypes.c_char_ptr_type, PyrexTypes.c_uchar_ptr_type, + PyrexTypes.c_const_char_ptr_type, PyrexTypes.c_const_uchar_ptr_type))): if type_tuple[1].is_pyobject: return default elif env.directives['c_string_encoding'] in ('ascii', 'default'): @@ -151,9 +151,9 @@ def check_negative_indices(*nodes): Used to find (potential) bugs inside of "wraparound=False" sections. """ for node in nodes: - if node is None or ( - not isinstance(node.constant_result, _py_int_types) and - not isinstance(node.constant_result, float)): + if node is None or ( + not isinstance(node.constant_result, _py_int_types) and + not isinstance(node.constant_result, float)): continue if node.constant_result < 0: warning(node.pos, @@ -187,111 +187,111 @@ def infer_sequence_item_type(env, seq_node, index_node=None, seq_type=None): return item_types.pop() return None - -def make_dedup_key(outer_type, item_nodes): - """ - Recursively generate a deduplication key from a sequence of values. - Includes Cython node types to work around the fact that (1, 2.0) == (1.0, 2), for example. - - @param outer_type: The type of the outer container. - @param item_nodes: A sequence of constant nodes that will be traversed recursively. - @return: A tuple that can be used as a dict key for deduplication. - """ - item_keys = [ - (py_object_type, None, type(None)) if node is None - # For sequences and their "mult_factor", see TupleNode. - else make_dedup_key(node.type, [node.mult_factor if node.is_literal else None] + node.args) if node.is_sequence_constructor - else make_dedup_key(node.type, (node.start, node.stop, node.step)) if node.is_slice - # For constants, look at the Python value type if we don't know the concrete Cython type. - else (node.type, node.constant_result, - type(node.constant_result) if node.type is py_object_type else None) if node.has_constant_result() - else None # something we cannot handle => short-circuit below - for node in item_nodes - ] - if None in item_keys: - return None - return outer_type, tuple(item_keys) - - -# Returns a block of code to translate the exception, -# plus a boolean indicating whether to check for Python exceptions. -def get_exception_handler(exception_value): - if exception_value is None: - return "__Pyx_CppExn2PyErr();", False - elif (exception_value.type == PyrexTypes.c_char_type - and exception_value.value == '*'): - return "__Pyx_CppExn2PyErr();", True - elif exception_value.type.is_pyobject: - return ( - 'try { throw; } catch(const std::exception& exn) {' - 'PyErr_SetString(%s, exn.what());' - '} catch(...) { PyErr_SetNone(%s); }' % ( - exception_value.entry.cname, - exception_value.entry.cname), - False) - else: - return ( - '%s(); if (!PyErr_Occurred())' - 'PyErr_SetString(PyExc_RuntimeError, ' - '"Error converting c++ exception.");' % ( - exception_value.entry.cname), - False) - -def maybe_check_py_error(code, check_py_exception, pos, nogil): - if check_py_exception: - if nogil: - code.putln(code.error_goto_if("__Pyx_ErrOccurredWithGIL()", pos)) - else: - code.putln(code.error_goto_if("PyErr_Occurred()", pos)) - -def translate_cpp_exception(code, pos, inside, py_result, exception_value, nogil): - raise_py_exception, check_py_exception = get_exception_handler(exception_value) - code.putln("try {") - code.putln("%s" % inside) - if py_result: - code.putln(code.error_goto_if_null(py_result, pos)) - maybe_check_py_error(code, check_py_exception, pos, nogil) - code.putln("} catch(...) {") - if nogil: - code.put_ensure_gil(declare_gilstate=True) - code.putln(raise_py_exception) - if nogil: - code.put_release_ensured_gil() - code.putln(code.error_goto(pos)) - code.putln("}") - -# Used to handle the case where an lvalue expression and an overloaded assignment -# both have an exception declaration. -def translate_double_cpp_exception(code, pos, lhs_type, lhs_code, rhs_code, - lhs_exc_val, assign_exc_val, nogil): - handle_lhs_exc, lhc_check_py_exc = get_exception_handler(lhs_exc_val) - handle_assignment_exc, assignment_check_py_exc = get_exception_handler(assign_exc_val) - code.putln("try {") - code.putln(lhs_type.declaration_code("__pyx_local_lvalue = %s;" % lhs_code)) - maybe_check_py_error(code, lhc_check_py_exc, pos, nogil) - code.putln("try {") - code.putln("__pyx_local_lvalue = %s;" % rhs_code) - maybe_check_py_error(code, assignment_check_py_exc, pos, nogil) - # Catch any exception from the overloaded assignment. - code.putln("} catch(...) {") - if nogil: - code.put_ensure_gil(declare_gilstate=True) - code.putln(handle_assignment_exc) - if nogil: - code.put_release_ensured_gil() - code.putln(code.error_goto(pos)) - code.putln("}") - # Catch any exception from evaluating lhs. - code.putln("} catch(...) {") - if nogil: - code.put_ensure_gil(declare_gilstate=True) - code.putln(handle_lhs_exc) - if nogil: - code.put_release_ensured_gil() - code.putln(code.error_goto(pos)) - code.putln('}') - - + +def make_dedup_key(outer_type, item_nodes): + """ + Recursively generate a deduplication key from a sequence of values. + Includes Cython node types to work around the fact that (1, 2.0) == (1.0, 2), for example. + + @param outer_type: The type of the outer container. + @param item_nodes: A sequence of constant nodes that will be traversed recursively. + @return: A tuple that can be used as a dict key for deduplication. + """ + item_keys = [ + (py_object_type, None, type(None)) if node is None + # For sequences and their "mult_factor", see TupleNode. + else make_dedup_key(node.type, [node.mult_factor if node.is_literal else None] + node.args) if node.is_sequence_constructor + else make_dedup_key(node.type, (node.start, node.stop, node.step)) if node.is_slice + # For constants, look at the Python value type if we don't know the concrete Cython type. + else (node.type, node.constant_result, + type(node.constant_result) if node.type is py_object_type else None) if node.has_constant_result() + else None # something we cannot handle => short-circuit below + for node in item_nodes + ] + if None in item_keys: + return None + return outer_type, tuple(item_keys) + + +# Returns a block of code to translate the exception, +# plus a boolean indicating whether to check for Python exceptions. +def get_exception_handler(exception_value): + if exception_value is None: + return "__Pyx_CppExn2PyErr();", False + elif (exception_value.type == PyrexTypes.c_char_type + and exception_value.value == '*'): + return "__Pyx_CppExn2PyErr();", True + elif exception_value.type.is_pyobject: + return ( + 'try { throw; } catch(const std::exception& exn) {' + 'PyErr_SetString(%s, exn.what());' + '} catch(...) { PyErr_SetNone(%s); }' % ( + exception_value.entry.cname, + exception_value.entry.cname), + False) + else: + return ( + '%s(); if (!PyErr_Occurred())' + 'PyErr_SetString(PyExc_RuntimeError, ' + '"Error converting c++ exception.");' % ( + exception_value.entry.cname), + False) + +def maybe_check_py_error(code, check_py_exception, pos, nogil): + if check_py_exception: + if nogil: + code.putln(code.error_goto_if("__Pyx_ErrOccurredWithGIL()", pos)) + else: + code.putln(code.error_goto_if("PyErr_Occurred()", pos)) + +def translate_cpp_exception(code, pos, inside, py_result, exception_value, nogil): + raise_py_exception, check_py_exception = get_exception_handler(exception_value) + code.putln("try {") + code.putln("%s" % inside) + if py_result: + code.putln(code.error_goto_if_null(py_result, pos)) + maybe_check_py_error(code, check_py_exception, pos, nogil) + code.putln("} catch(...) {") + if nogil: + code.put_ensure_gil(declare_gilstate=True) + code.putln(raise_py_exception) + if nogil: + code.put_release_ensured_gil() + code.putln(code.error_goto(pos)) + code.putln("}") + +# Used to handle the case where an lvalue expression and an overloaded assignment +# both have an exception declaration. +def translate_double_cpp_exception(code, pos, lhs_type, lhs_code, rhs_code, + lhs_exc_val, assign_exc_val, nogil): + handle_lhs_exc, lhc_check_py_exc = get_exception_handler(lhs_exc_val) + handle_assignment_exc, assignment_check_py_exc = get_exception_handler(assign_exc_val) + code.putln("try {") + code.putln(lhs_type.declaration_code("__pyx_local_lvalue = %s;" % lhs_code)) + maybe_check_py_error(code, lhc_check_py_exc, pos, nogil) + code.putln("try {") + code.putln("__pyx_local_lvalue = %s;" % rhs_code) + maybe_check_py_error(code, assignment_check_py_exc, pos, nogil) + # Catch any exception from the overloaded assignment. + code.putln("} catch(...) {") + if nogil: + code.put_ensure_gil(declare_gilstate=True) + code.putln(handle_assignment_exc) + if nogil: + code.put_release_ensured_gil() + code.putln(code.error_goto(pos)) + code.putln("}") + # Catch any exception from evaluating lhs. + code.putln("} catch(...) {") + if nogil: + code.put_ensure_gil(declare_gilstate=True) + code.putln(handle_lhs_exc) + if nogil: + code.put_release_ensured_gil() + code.putln(code.error_goto(pos)) + code.putln('}') + + class ExprNode(Node): # subexprs [string] Class var holding names of subexpr node attrs # type PyrexType Type of the result @@ -434,18 +434,18 @@ class ExprNode(Node): is_sequence_constructor = False is_dict_literal = False - is_set_literal = False + is_set_literal = False is_string_literal = False is_attribute = False is_subscript = False - is_slice = False - - is_buffer_access = False - is_memview_index = False - is_memview_slice = False - is_memview_broadcast = False - is_memview_copy_assignment = False - + is_slice = False + + is_buffer_access = False + is_memview_index = False + is_memview_slice = False + is_memview_broadcast = False + is_memview_copy_assignment = False + saved_subexpr_nodes = None is_temp = False is_target = False @@ -505,12 +505,12 @@ class ExprNode(Node): assert(type_ is not None) return to_pythran(self, type_) - def is_c_result_required(self): - """ - Subtypes may return False here if result temp allocation can be skipped. - """ - return True - + def is_c_result_required(self): + """ + Subtypes may return False here if result temp allocation can be skipped. + """ + return True + def result_as(self, type = None): # Return the result code cast to the specified C type. if (self.is_temp and self.type.is_pyobject and @@ -635,14 +635,14 @@ class ExprNode(Node): # can't be modified as part of globals or closures. return self.is_literal or self.is_temp or self.type.is_array or self.type.is_cfunction - def inferable_item_node(self, index=0): - """ - Return a node that represents the (type) result of an indexing operation, - e.g. for tuple unpacking or iteration. - """ - return IndexNode(self.pos, base=self, index=IntNode( - self.pos, value=str(index), constant_result=index, type=PyrexTypes.c_py_ssize_t_type)) - + def inferable_item_node(self, index=0): + """ + Return a node that represents the (type) result of an indexing operation, + e.g. for tuple unpacking or iteration. + """ + return IndexNode(self.pos, base=self, index=IntNode( + self.pos, value=str(index), constant_result=index, type=PyrexTypes.c_py_ssize_t_type)) + # --------------- Type Analysis ------------------ def analyse_as_module(self, env): @@ -718,9 +718,9 @@ class ExprNode(Node): if not type.is_void: if type.is_pyobject: type = PyrexTypes.py_object_type - elif not (self.result_is_used or type.is_memoryviewslice or self.is_c_result_required()): - self.temp_code = None - return + elif not (self.result_is_used or type.is_memoryviewslice or self.is_c_result_required()): + self.temp_code = None + return self.temp_code = code.funcstate.allocate_temp( type, manage_ref=self.use_managed_ref) else: @@ -796,8 +796,8 @@ class ExprNode(Node): elif self.type.is_memoryviewslice: code.put_xdecref_memoryviewslice( self.result(), have_gil=not self.in_nogil_context) - code.putln("%s.memview = NULL;" % self.result()) - code.putln("%s.data = NULL;" % self.result()) + code.putln("%s.memview = NULL;" % self.result()) + code.putln("%s.data = NULL;" % self.result()) else: # Already done if self.is_temp self.generate_subexpr_disposal_code(code) @@ -822,8 +822,8 @@ class ExprNode(Node): else: self.generate_subexpr_disposal_code(code) - def generate_assignment_code(self, rhs, code, overloaded_assignment=False, - exception_check=None, exception_value=None): + def generate_assignment_code(self, rhs, code, overloaded_assignment=False, + exception_check=None, exception_value=None): # Stub method for nodes which are not legal as # the LHS of an assignment. An error will have # been reported earlier. @@ -879,8 +879,8 @@ class ExprNode(Node): if self.check_for_coercion_error(dst_type, env): return self - used_as_reference = dst_type.is_reference - if used_as_reference and not src_type.is_reference: + used_as_reference = dst_type.is_reference + if used_as_reference and not src_type.is_reference: dst_type = dst_type.ref_base_type if src_type.is_const: @@ -903,9 +903,9 @@ class ExprNode(Node): if src_type.is_fused: error(self.pos, "Type is not specialized") - elif src_type.is_null_ptr and dst_type.is_ptr: - # NULL can be implicitly cast to any pointer type - return self + elif src_type.is_null_ptr and dst_type.is_ptr: + # NULL can be implicitly cast to any pointer type + return self else: error(self.pos, "Cannot coerce to a type that is not specialized") @@ -923,10 +923,10 @@ class ExprNode(Node): if src.type.is_pyobject: src = CoerceToMemViewSliceNode(src, dst_type, env) elif src.type.is_array: - src = CythonArrayNode.from_carray(src, env).coerce_to(dst_type, env) + src = CythonArrayNode.from_carray(src, env).coerce_to(dst_type, env) elif not src_type.is_error: error(self.pos, - "Cannot convert '%s' to memoryviewslice" % (src_type,)) + "Cannot convert '%s' to memoryviewslice" % (src_type,)) else: if src.type.writable_needed: dst_type.writable_needed = True @@ -961,10 +961,10 @@ class ExprNode(Node): # Else, we need to convert the Pythran expression to a Python object src = CoerceToPyTypeNode(src, env, type=dst_type) elif src.type.is_pyobject: - if used_as_reference and dst_type.is_cpp_class: - warning( - self.pos, - "Cannot pass Python object as C++ data structure reference (%s &), will pass by copy." % dst_type) + if used_as_reference and dst_type.is_cpp_class: + warning( + self.pos, + "Cannot pass Python object as C++ data structure reference (%s &), will pass by copy." % dst_type) src = CoerceFromPyTypeNode(dst_type, src, env) elif (dst_type.is_complex and src_type != dst_type @@ -974,8 +974,8 @@ class ExprNode(Node): # Added the string comparison, since for c types that # is enough, but Cython gets confused when the types are # in different pxi files. - # TODO: Remove this hack and require shared declarations. - if not (src.type == dst_type or str(src.type) == str(dst_type) or dst_type.assignable_from(src_type)): + # TODO: Remove this hack and require shared declarations. + if not (src.type == dst_type or str(src.type) == str(dst_type) or dst_type.assignable_from(src_type)): self.fail_assignment(dst_type) return src @@ -1013,15 +1013,15 @@ class ExprNode(Node): elif type.is_pyobject or type.is_int or type.is_ptr or type.is_float: return CoerceToBooleanNode(self, env) elif type.is_cpp_class and type.scope and type.scope.lookup("operator bool"): - return SimpleCallNode( - self.pos, - function=AttributeNode( + return SimpleCallNode( + self.pos, + function=AttributeNode( self.pos, obj=self, attribute=StringEncoding.EncodedString('operator bool')), - args=[]).analyse_types(env) - elif type.is_ctuple: - bool_value = len(type.components) == 0 - return BoolNode(self.pos, value=bool_value, - constant_result=bool_value) + args=[]).analyse_types(env) + elif type.is_ctuple: + bool_value = len(type.components) == 0 + return BoolNode(self.pos, value=bool_value, + constant_result=bool_value) else: error(self.pos, "Type '%s' not acceptable as a boolean" % type) return self @@ -1209,10 +1209,10 @@ class BoolNode(ConstNode): return str(int(self.value)) def coerce_to(self, dst_type, env): - if dst_type == self.type: - return self - if dst_type is py_object_type and self.type is Builtin.bool_type: - return self + if dst_type == self.type: + return self + if dst_type is py_object_type and self.type is Builtin.bool_type: + return self if dst_type.is_pyobject and self.type.is_int: return BoolNode( self.pos, value=self.value, @@ -1272,7 +1272,7 @@ class IntNode(ConstNode): # we ignore 'is_c_literal = True' and instead map signed 32bit # integers as C long values if self.is_c_literal or \ - not self.has_constant_result() or \ + not self.has_constant_result() or \ self.unsigned or self.longness == 'LL': # clearly a C literal rank = (self.longness == 'LL') and 2 or 1 @@ -1302,12 +1302,12 @@ class IntNode(ConstNode): constant_result=not_a_constant) if dst_type.is_numeric and not dst_type.is_complex: node = IntNode(self.pos, value=self.value, constant_result=self.constant_result, - type=dst_type, is_c_literal=True, + type=dst_type, is_c_literal=True, unsigned=self.unsigned, longness=self.longness) return node elif dst_type.is_pyobject: node = IntNode(self.pos, value=self.value, constant_result=self.constant_result, - type=PyrexTypes.py_object_type, is_c_literal=False, + type=PyrexTypes.py_object_type, is_c_literal=False, unsigned=self.unsigned, longness=self.longness) else: # FIXME: not setting the type here to keep it working with @@ -1335,43 +1335,43 @@ class IntNode(ConstNode): self.result_code = self.get_constant_c_result_code() def get_constant_c_result_code(self): - unsigned, longness = self.unsigned, self.longness - literal = self.value_as_c_integer_string() - if not (unsigned or longness) and self.type.is_int and literal[0] == '-' and literal[1] != '0': - # negative decimal literal => guess longness from type to prevent wrap-around - if self.type.rank >= PyrexTypes.c_longlong_type.rank: - longness = 'LL' - elif self.type.rank >= PyrexTypes.c_long_type.rank: - longness = 'L' - return literal + unsigned + longness + unsigned, longness = self.unsigned, self.longness + literal = self.value_as_c_integer_string() + if not (unsigned or longness) and self.type.is_int and literal[0] == '-' and literal[1] != '0': + # negative decimal literal => guess longness from type to prevent wrap-around + if self.type.rank >= PyrexTypes.c_longlong_type.rank: + longness = 'LL' + elif self.type.rank >= PyrexTypes.c_long_type.rank: + longness = 'L' + return literal + unsigned + longness def value_as_c_integer_string(self): value = self.value - if len(value) <= 2: - # too short to go wrong (and simplifies code below) - return value - neg_sign = '' - if value[0] == '-': - neg_sign = '-' - value = value[1:] - if value[0] == '0': - literal_type = value[1] # 0'o' - 0'b' - 0'x' - # 0x123 hex literals and 0123 octal literals work nicely in C - # but C-incompatible Py3 oct/bin notations need conversion - if neg_sign and literal_type in 'oOxX0123456789' and value[2:].isdigit(): - # negative hex/octal literal => prevent C compiler from using - # unsigned integer types by converting to decimal (see C standard 6.4.4.1) - value = str(Utils.str_to_number(value)) - elif literal_type in 'oO': - value = '0' + value[2:] # '0o123' => '0123' - elif literal_type in 'bB': - value = str(int(value[2:], 2)) - elif value.isdigit() and not self.unsigned and not self.longness: - if not neg_sign: - # C compilers do not consider unsigned types for decimal literals, - # but they do for hex (see C standard 6.4.4.1) - value = '0x%X' % int(value) - return neg_sign + value + if len(value) <= 2: + # too short to go wrong (and simplifies code below) + return value + neg_sign = '' + if value[0] == '-': + neg_sign = '-' + value = value[1:] + if value[0] == '0': + literal_type = value[1] # 0'o' - 0'b' - 0'x' + # 0x123 hex literals and 0123 octal literals work nicely in C + # but C-incompatible Py3 oct/bin notations need conversion + if neg_sign and literal_type in 'oOxX0123456789' and value[2:].isdigit(): + # negative hex/octal literal => prevent C compiler from using + # unsigned integer types by converting to decimal (see C standard 6.4.4.1) + value = str(Utils.str_to_number(value)) + elif literal_type in 'oO': + value = '0' + value[2:] # '0o123' => '0123' + elif literal_type in 'bB': + value = str(int(value[2:], 2)) + elif value.isdigit() and not self.unsigned and not self.longness: + if not neg_sign: + # C compilers do not consider unsigned types for decimal literals, + # but they do for hex (see C standard 6.4.4.1) + value = '0x%X' % int(value) + return neg_sign + value def calculate_result_code(self): return self.result_code @@ -1409,7 +1409,7 @@ class FloatNode(ConstNode): def get_constant_c_result_code(self): strval = self.value - assert isinstance(strval, basestring) + assert isinstance(strval, basestring) cmpval = repr(float(strval)) if cmpval == 'nan': return "(Py_HUGE_VAL * 0)" @@ -1433,12 +1433,12 @@ def _analyse_name_as_type(name, pos, env): if type is not None: return type - global_entry = env.global_scope().lookup(name) - if global_entry and global_entry.type and ( - global_entry.type.is_extension_type - or global_entry.type.is_struct_or_union - or global_entry.type.is_builtin_type - or global_entry.type.is_cpp_class): + global_entry = env.global_scope().lookup(name) + if global_entry and global_entry.type and ( + global_entry.type.is_extension_type + or global_entry.type.is_struct_or_union + or global_entry.type.is_builtin_type + or global_entry.type.is_cpp_class): return global_entry.type from .TreeFragment import TreeFragment @@ -1470,11 +1470,11 @@ class BytesNode(ConstNode): self.constant_result = self.value def as_sliced_node(self, start, stop, step=None): - value = StringEncoding.bytes_literal(self.value[start:stop:step], self.value.encoding) - return BytesNode(self.pos, value=value, constant_result=value) + value = StringEncoding.bytes_literal(self.value[start:stop:step], self.value.encoding) + return BytesNode(self.pos, value=value, constant_result=value) def compile_time_value(self, denv): - return self.value.byteencode() + return self.value.byteencode() def analyse_as_type(self, env): return _analyse_name_as_type(self.value.decode('ISO8859-1'), self.pos, env) @@ -1501,20 +1501,20 @@ class BytesNode(ConstNode): return CharNode(self.pos, value=self.value, constant_result=ord(self.value)) - node = BytesNode(self.pos, value=self.value, constant_result=self.constant_result) + node = BytesNode(self.pos, value=self.value, constant_result=self.constant_result) if dst_type.is_pyobject: if dst_type in (py_object_type, Builtin.bytes_type): node.type = Builtin.bytes_type else: self.check_for_coercion_error(dst_type, env, fail=True) return node - elif dst_type in (PyrexTypes.c_char_ptr_type, PyrexTypes.c_const_char_ptr_type): + elif dst_type in (PyrexTypes.c_char_ptr_type, PyrexTypes.c_const_char_ptr_type): node.type = dst_type return node - elif dst_type in (PyrexTypes.c_uchar_ptr_type, PyrexTypes.c_const_uchar_ptr_type, PyrexTypes.c_void_ptr_type): - node.type = (PyrexTypes.c_const_char_ptr_type if dst_type == PyrexTypes.c_const_uchar_ptr_type - else PyrexTypes.c_char_ptr_type) - return CastNode(node, dst_type) + elif dst_type in (PyrexTypes.c_uchar_ptr_type, PyrexTypes.c_const_uchar_ptr_type, PyrexTypes.c_void_ptr_type): + node.type = (PyrexTypes.c_const_char_ptr_type if dst_type == PyrexTypes.c_const_uchar_ptr_type + else PyrexTypes.c_char_ptr_type) + return CastNode(node, dst_type) elif dst_type.assignable_from(PyrexTypes.c_char_ptr_type): # Exclude the case of passing a C string literal into a non-const C++ string. if not dst_type.is_cpp_class or dst_type.is_const: @@ -1528,15 +1528,15 @@ class BytesNode(ConstNode): def generate_evaluation_code(self, code): if self.type.is_pyobject: - result = code.get_py_string_const(self.value) - elif self.type.is_const: - result = code.get_string_const(self.value) + result = code.get_py_string_const(self.value) + elif self.type.is_const: + result = code.get_string_const(self.value) else: - # not const => use plain C string literal and cast to mutable type - literal = self.value.as_c_string_literal() - # C++ may require a cast - result = typecast(self.type, PyrexTypes.c_void_ptr_type, literal) - self.result_code = result + # not const => use plain C string literal and cast to mutable type + literal = self.value.as_c_string_literal() + # C++ may require a cast + result = typecast(self.type, PyrexTypes.c_void_ptr_type, literal) + self.result_code = result def get_constant_c_result_code(self): return None # FIXME @@ -1570,8 +1570,8 @@ class UnicodeNode(ConstNode): value = StringEncoding.EncodedString(self.value[start:stop:step]) value.encoding = self.value.encoding if self.bytes_value is not None: - bytes_value = StringEncoding.bytes_literal( - self.bytes_value[start:stop:step], self.bytes_value.encoding) + bytes_value = StringEncoding.bytes_literal( + self.bytes_value[start:stop:step], self.bytes_value.encoding) else: bytes_value = None return UnicodeNode( @@ -1634,17 +1634,17 @@ class UnicodeNode(ConstNode): self.result_code = code.get_py_const(py_object_type, 'ustring') data_cname = code.get_string_const( StringEncoding.BytesLiteral(self.value.encode('unicode_escape'))) - const_code = code.get_cached_constants_writer(self.result_code) - if const_code is None: - return # already initialised - const_code.mark_pos(self.pos) - const_code.putln( + const_code = code.get_cached_constants_writer(self.result_code) + if const_code is None: + return # already initialised + const_code.mark_pos(self.pos) + const_code.putln( "%s = PyUnicode_DecodeUnicodeEscape(%s, sizeof(%s) - 1, NULL); %s" % ( self.result_code, data_cname, data_cname, - const_code.error_goto_if_null(self.result_code, self.pos))) - const_code.put_error_if_neg( + const_code.error_goto_if_null(self.result_code, self.pos))) + const_code.put_error_if_neg( self.pos, "__Pyx_PyUnicode_READY(%s)" % self.result_code) else: self.result_code = code.get_py_string_const(self.value) @@ -1720,15 +1720,15 @@ class StringNode(PyConstNode): return self.result_code def compile_time_value(self, env): - if self.value.is_unicode: - return self.value - if not IS_PYTHON3: - # use plain str/bytes object in Py2 - return self.value.byteencode() - # in Py3, always return a Unicode string - if self.unicode_value is not None: - return self.unicode_value - return self.value.decode('iso8859-1') + if self.value.is_unicode: + return self.value + if not IS_PYTHON3: + # use plain str/bytes object in Py2 + return self.value.byteencode() + # in Py3, always return a Unicode string + if self.unicode_value is not None: + return self.unicode_value + return self.value.decode('iso8859-1') class IdentifierStringNode(StringNode): @@ -1820,7 +1820,7 @@ class NewExprNode(AtomicExprNode): pass def calculate_result_code(self): - return "new " + self.class_type.empty_declaration_code() + return "new " + self.class_type.empty_declaration_code() class NameNode(AtomicExprNode): @@ -2023,25 +2023,25 @@ class NameNode(AtomicExprNode): def analyse_target_types(self, env): self.analyse_entry(env, is_target=True) - entry = self.entry - if entry.is_cfunction and entry.as_variable: - # FIXME: unify "is_overridable" flags below - if (entry.is_overridable or entry.type.is_overridable) or not self.is_lvalue() and entry.fused_cfunction: - # We need this for assigning to cpdef names and for the fused 'def' TreeFragment - entry = self.entry = entry.as_variable - self.type = entry.type + entry = self.entry + if entry.is_cfunction and entry.as_variable: + # FIXME: unify "is_overridable" flags below + if (entry.is_overridable or entry.type.is_overridable) or not self.is_lvalue() and entry.fused_cfunction: + # We need this for assigning to cpdef names and for the fused 'def' TreeFragment + entry = self.entry = entry.as_variable + self.type = entry.type if self.type.is_const: error(self.pos, "Assignment to const '%s'" % self.name) if self.type.is_reference: error(self.pos, "Assignment to reference '%s'" % self.name) if not self.is_lvalue(): - error(self.pos, "Assignment to non-lvalue '%s'" % self.name) + error(self.pos, "Assignment to non-lvalue '%s'" % self.name) self.type = PyrexTypes.error_type - entry.used = 1 - if entry.type.is_buffer: + entry.used = 1 + if entry.type.is_buffer: from . import Buffer - Buffer.used_buffer_aux_vars(entry) + Buffer.used_buffer_aux_vars(entry) return self def analyse_rvalue_entry(self, env): @@ -2096,11 +2096,11 @@ class NameNode(AtomicExprNode): entry = self.entry if entry.is_type and entry.type.is_extension_type: self.type_entry = entry - if entry.is_type and entry.type.is_enum: - py_entry = Symtab.Entry(self.name, None, py_object_type) - py_entry.is_pyglobal = True - py_entry.scope = self.entry.scope - self.entry = py_entry + if entry.is_type and entry.type.is_enum: + py_entry = Symtab.Entry(self.name, None, py_object_type) + py_entry.is_pyglobal = True + py_entry.scope = self.entry.scope + self.entry = py_entry elif not (entry.is_const or entry.is_variable or entry.is_builtin or entry.is_cfunction or entry.is_cpp_class): @@ -2170,13 +2170,13 @@ class NameNode(AtomicExprNode): return True def is_lvalue(self): - return ( - self.entry.is_variable and + return ( + self.entry.is_variable and not self.entry.is_readonly - ) or ( - self.entry.is_cfunction and - self.entry.is_overridable - ) + ) or ( + self.entry.is_cfunction and + self.entry.is_overridable + ) def is_addressable(self): return self.entry.is_variable and not self.type.is_memoryviewslice @@ -2197,8 +2197,8 @@ class NameNode(AtomicExprNode): entry = self.entry if entry is None: return # There was an error earlier - if entry.utility_code: - code.globalstate.use_utility_code(entry.utility_code) + if entry.utility_code: + code.globalstate.use_utility_code(entry.utility_code) if entry.is_builtin and entry.is_const: return # Lookup already cached elif entry.is_pyclass_attr: @@ -2219,7 +2219,7 @@ class NameNode(AtomicExprNode): code.globalstate.use_utility_code( UtilityCode.load_cached("GetModuleGlobalName", "ObjectHandling.c")) code.putln( - '__Pyx_GetModuleGlobalName(%s, %s);' % ( + '__Pyx_GetModuleGlobalName(%s, %s);' % ( self.result(), interned_cname)) if not self.cf_is_null: @@ -2248,7 +2248,7 @@ class NameNode(AtomicExprNode): code.globalstate.use_utility_code( UtilityCode.load_cached("GetModuleGlobalName", "ObjectHandling.c")) code.putln( - '__Pyx_GetModuleGlobalName(%s, %s); %s' % ( + '__Pyx_GetModuleGlobalName(%s, %s); %s' % ( self.result(), interned_cname, code.error_goto_if_null(self.result(), self.pos))) @@ -2257,7 +2257,7 @@ class NameNode(AtomicExprNode): code.globalstate.use_utility_code( UtilityCode.load_cached("GetNameInClass", "ObjectHandling.c")) code.putln( - '__Pyx_GetNameInClass(%s, %s, %s); %s' % ( + '__Pyx_GetNameInClass(%s, %s, %s); %s' % ( self.result(), entry.scope.namespace_cname, interned_cname, @@ -2275,15 +2275,15 @@ class NameNode(AtomicExprNode): if null_code and raise_unbound and (entry.type.is_pyobject or memslice_check): code.put_error_if_unbound(self.pos, entry, self.in_nogil_context) - def generate_assignment_code(self, rhs, code, overloaded_assignment=False, - exception_check=None, exception_value=None): + def generate_assignment_code(self, rhs, code, overloaded_assignment=False, + exception_check=None, exception_value=None): #print "NameNode.generate_assignment_code:", self.name ### entry = self.entry if entry is None: return # There was an error earlier if (self.entry.type.is_ptr and isinstance(rhs, ListNode) - and not self.lhs_of_first_assignment and not rhs.in_module_scope): + and not self.lhs_of_first_assignment and not rhs.in_module_scope): error(self.pos, "Literal list must be assigned to pointer at time of declaration") # is_pyglobal seems to be True for module level-globals only. @@ -2367,22 +2367,22 @@ class NameNode(AtomicExprNode): code.put_giveref(rhs.py_result()) if not self.type.is_memoryviewslice: if not assigned: - if overloaded_assignment: - result = rhs.result() - if exception_check == '+': - translate_cpp_exception( - code, self.pos, - '%s = %s;' % (self.result(), result), - self.result() if self.type.is_pyobject else None, - exception_value, self.in_nogil_context) - else: - code.putln('%s = %s;' % (self.result(), result)) - else: - result = rhs.result_as(self.ctype()) + if overloaded_assignment: + result = rhs.result() + if exception_check == '+': + translate_cpp_exception( + code, self.pos, + '%s = %s;' % (self.result(), result), + self.result() if self.type.is_pyobject else None, + exception_value, self.in_nogil_context) + else: + code.putln('%s = %s;' % (self.result(), result)) + else: + result = rhs.result_as(self.ctype()) if is_pythran_expr(self.type): code.putln('new (&%s) decltype(%s){%s};' % (self.result(), self.result(), result)) - elif result != self.result(): + elif result != self.result(): code.putln('%s = %s;' % (self.result(), result)) if debug_disposal_code: print("NameNode.generate_assignment_code:") @@ -2456,10 +2456,10 @@ class NameNode(AtomicExprNode): del_code = '__Pyx_PyObject_DelAttrStr(%s, %s)' % ( Naming.module_cname, interned_cname) if ignore_nonexisting: - code.putln( - 'if (unlikely(%s < 0)) {' - ' if (likely(PyErr_ExceptionMatches(PyExc_AttributeError))) PyErr_Clear(); else %s ' - '}' % (del_code, code.error_goto(self.pos))) + code.putln( + 'if (unlikely(%s < 0)) {' + ' if (likely(PyErr_ExceptionMatches(PyExc_AttributeError))) PyErr_Clear(); else %s ' + '}' % (del_code, code.error_goto(self.pos))) else: code.put_error_if_neg(self.pos, del_code) elif self.entry.type.is_pyobject or self.entry.type.is_memoryviewslice: @@ -2566,24 +2566,24 @@ class ImportNode(ExprNode): name_list_code = self.name_list.py_result() else: name_list_code = "0" - - code.globalstate.use_utility_code(UtilityCode.load_cached("Import", "ImportExport.c")) - import_code = "__Pyx_Import(%s, %s, %d)" % ( - self.module_name.py_result(), - name_list_code, - self.level) - - if (self.level <= 0 and - self.module_name.is_string_literal and - self.module_name.value in utility_code_for_imports): - helper_func, code_name, code_file = utility_code_for_imports[self.module_name.value] - code.globalstate.use_utility_code(UtilityCode.load_cached(code_name, code_file)) - import_code = '%s(%s)' % (helper_func, import_code) - - code.putln("%s = %s; %s" % ( - self.result(), - import_code, - code.error_goto_if_null(self.result(), self.pos))) + + code.globalstate.use_utility_code(UtilityCode.load_cached("Import", "ImportExport.c")) + import_code = "__Pyx_Import(%s, %s, %d)" % ( + self.module_name.py_result(), + name_list_code, + self.level) + + if (self.level <= 0 and + self.module_name.is_string_literal and + self.module_name.value in utility_code_for_imports): + helper_func, code_name, code_file = utility_code_for_imports[self.module_name.value] + code.globalstate.use_utility_code(UtilityCode.load_cached(code_name, code_file)) + import_code = '%s(%s)' % (helper_func, import_code) + + code.putln("%s = %s; %s" % ( + self.result(), + import_code, + code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) @@ -2599,7 +2599,7 @@ class IteratorNode(ExprNode): counter_cname = None cpp_iterator_cname = None reversed = False # currently only used for list/tuple types (see Optimize.py) - is_async = False + is_async = False subexprs = ['sequence'] @@ -2613,7 +2613,7 @@ class IteratorNode(ExprNode): self.analyse_cpp_types(env) else: self.sequence = self.sequence.coerce_to_pyobject(env) - if self.sequence.type in (list_type, tuple_type): + if self.sequence.type in (list_type, tuple_type): self.sequence = self.sequence.as_none_safe_node("'NoneType' object is not iterable") self.is_temp = 1 return self @@ -2701,8 +2701,8 @@ class IteratorNode(ExprNode): return if sequence_type.is_array or sequence_type.is_ptr: raise InternalError("for in carray slice not transformed") - - is_builtin_sequence = sequence_type in (list_type, tuple_type) + + is_builtin_sequence = sequence_type in (list_type, tuple_type) if not is_builtin_sequence: # reversed() not currently optimised (see Optimize.py) assert not self.reversed, "internal error: reversed() only implemented for list/tuple objects" @@ -2712,7 +2712,7 @@ class IteratorNode(ExprNode): "if (likely(PyList_CheckExact(%s)) || PyTuple_CheckExact(%s)) {" % ( self.sequence.py_result(), self.sequence.py_result())) - + if is_builtin_sequence or self.may_be_a_sequence: self.counter_cname = code.funcstate.allocate_temp( PyrexTypes.c_py_ssize_t_type, manage_ref=False) @@ -2723,25 +2723,25 @@ class IteratorNode(ExprNode): init_value = 'PyTuple_GET_SIZE(%s) - 1' % self.result() else: init_value = '0' - code.putln("%s = %s; __Pyx_INCREF(%s); %s = %s;" % ( - self.result(), - self.sequence.py_result(), - self.result(), - self.counter_cname, - init_value)) + code.putln("%s = %s; __Pyx_INCREF(%s); %s = %s;" % ( + self.result(), + self.sequence.py_result(), + self.result(), + self.counter_cname, + init_value)) if not is_builtin_sequence: self.iter_func_ptr = code.funcstate.allocate_temp(self._func_iternext_type, manage_ref=False) if self.may_be_a_sequence: code.putln("%s = NULL;" % self.iter_func_ptr) code.putln("} else {") code.put("%s = -1; " % self.counter_cname) - + code.putln("%s = PyObject_GetIter(%s); %s" % ( - self.result(), - self.sequence.py_result(), - code.error_goto_if_null(self.result(), self.pos))) + self.result(), + self.sequence.py_result(), + code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) - + # PyObject_GetIter() fails if "tp_iternext" is not set, but the check below # makes it visible to the C compiler that the pointer really isn't NULL, so that # it can distinguish between the special cases and the generic case @@ -2758,14 +2758,14 @@ class IteratorNode(ExprNode): item_count = len(self.sequence.args) if self.sequence.mult_factor is None: final_size = item_count - elif isinstance(self.sequence.mult_factor.constant_result, _py_int_types): + elif isinstance(self.sequence.mult_factor.constant_result, _py_int_types): final_size = item_count * self.sequence.mult_factor.constant_result code.putln("if (%s >= %s) break;" % (self.counter_cname, final_size)) if self.reversed: inc_dec = '--' else: inc_dec = '++' - code.putln("#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS") + code.putln("#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS") code.putln( "%s = Py%s_GET_ITEM(%s, %s); __Pyx_INCREF(%s); %s%s; %s" % ( result_name, @@ -2787,7 +2787,7 @@ class IteratorNode(ExprNode): self.counter_cname, inc_dec, code.error_goto_if_null(result_name, self.pos))) - code.put_gotref(result_name) + code.put_gotref(result_name) code.putln("#endif") def generate_iter_next_result_code(self, result_name, code): @@ -2854,7 +2854,7 @@ class IteratorNode(ExprNode): class NextNode(AtomicExprNode): # Used as part of for statement implementation. - # Implements result = next(iterator) + # Implements result = next(iterator) # Created during analyse_types phase. # The iterator is not owned by this node. # @@ -2864,14 +2864,14 @@ class NextNode(AtomicExprNode): AtomicExprNode.__init__(self, iterator.pos) self.iterator = iterator - def nogil_check(self, env): - # ignore - errors (if any) are already handled by IteratorNode - pass - + def nogil_check(self, env): + # ignore - errors (if any) are already handled by IteratorNode + pass + def type_dependencies(self, env): return self.iterator.type_dependencies(env) - def infer_type(self, env, iterator_type=None): + def infer_type(self, env, iterator_type=None): if iterator_type is None: iterator_type = self.iterator.infer_type(env) if iterator_type.is_ptr or iterator_type.is_array: @@ -2901,68 +2901,68 @@ class NextNode(AtomicExprNode): self.iterator.generate_iter_next_result_code(self.result(), code) -class AsyncIteratorNode(ExprNode): - # Used as part of 'async for' statement implementation. - # - # Implements result = sequence.__aiter__() - # - # sequence ExprNode - - subexprs = ['sequence'] - - is_async = True - type = py_object_type - is_temp = 1 - - def infer_type(self, env): - return py_object_type - - def analyse_types(self, env): - self.sequence = self.sequence.analyse_types(env) - if not self.sequence.type.is_pyobject: - error(self.pos, "async for loops not allowed on C/C++ types") - self.sequence = self.sequence.coerce_to_pyobject(env) - return self - - def generate_result_code(self, code): - code.globalstate.use_utility_code(UtilityCode.load_cached("AsyncIter", "Coroutine.c")) - code.putln("%s = __Pyx_Coroutine_GetAsyncIter(%s); %s" % ( - self.result(), - self.sequence.py_result(), - code.error_goto_if_null(self.result(), self.pos))) - code.put_gotref(self.result()) - - -class AsyncNextNode(AtomicExprNode): - # Used as part of 'async for' statement implementation. - # Implements result = iterator.__anext__() - # Created during analyse_types phase. - # The iterator is not owned by this node. - # - # iterator IteratorNode - - type = py_object_type - is_temp = 1 - - def __init__(self, iterator): - AtomicExprNode.__init__(self, iterator.pos) - self.iterator = iterator - - def infer_type(self, env): - return py_object_type - - def analyse_types(self, env): - return self - - def generate_result_code(self, code): - code.globalstate.use_utility_code(UtilityCode.load_cached("AsyncIter", "Coroutine.c")) - code.putln("%s = __Pyx_Coroutine_AsyncIterNext(%s); %s" % ( - self.result(), - self.iterator.py_result(), - code.error_goto_if_null(self.result(), self.pos))) - code.put_gotref(self.result()) - - +class AsyncIteratorNode(ExprNode): + # Used as part of 'async for' statement implementation. + # + # Implements result = sequence.__aiter__() + # + # sequence ExprNode + + subexprs = ['sequence'] + + is_async = True + type = py_object_type + is_temp = 1 + + def infer_type(self, env): + return py_object_type + + def analyse_types(self, env): + self.sequence = self.sequence.analyse_types(env) + if not self.sequence.type.is_pyobject: + error(self.pos, "async for loops not allowed on C/C++ types") + self.sequence = self.sequence.coerce_to_pyobject(env) + return self + + def generate_result_code(self, code): + code.globalstate.use_utility_code(UtilityCode.load_cached("AsyncIter", "Coroutine.c")) + code.putln("%s = __Pyx_Coroutine_GetAsyncIter(%s); %s" % ( + self.result(), + self.sequence.py_result(), + code.error_goto_if_null(self.result(), self.pos))) + code.put_gotref(self.result()) + + +class AsyncNextNode(AtomicExprNode): + # Used as part of 'async for' statement implementation. + # Implements result = iterator.__anext__() + # Created during analyse_types phase. + # The iterator is not owned by this node. + # + # iterator IteratorNode + + type = py_object_type + is_temp = 1 + + def __init__(self, iterator): + AtomicExprNode.__init__(self, iterator.pos) + self.iterator = iterator + + def infer_type(self, env): + return py_object_type + + def analyse_types(self, env): + return self + + def generate_result_code(self, code): + code.globalstate.use_utility_code(UtilityCode.load_cached("AsyncIter", "Coroutine.c")) + code.putln("%s = __Pyx_Coroutine_AsyncIterNext(%s); %s" % ( + self.result(), + self.iterator.py_result(), + code.error_goto_if_null(self.result(), self.pos))) + code.put_gotref(self.result()) + + class WithExitCallNode(ExprNode): # The __exit__() call of a 'with' statement. Used in both the # except and finally clauses. @@ -3004,14 +3004,14 @@ class WithExitCallNode(ExprNode): code.putln(code.error_goto_if_null(result_var, self.pos)) code.put_gotref(result_var) - + if self.await_expr: - # FIXME: result_var temp currently leaks into the closure + # FIXME: result_var temp currently leaks into the closure self.await_expr.generate_evaluation_code(code, source_cname=result_var, decref_source=True) code.putln("%s = %s;" % (result_var, self.await_expr.py_result())) self.await_expr.generate_post_assignment_code(code) self.await_expr.free_temps(code) - + if self.result_is_used: self.allocate_temp_result(code) code.putln("%s = __Pyx_PyObject_IsTrue(%s);" % (self.result(), result_var)) @@ -3123,59 +3123,59 @@ class RawCNameExprNode(ExprNode): #------------------------------------------------------------------- # -# F-strings -# -#------------------------------------------------------------------- - - -class JoinedStrNode(ExprNode): - # F-strings - # - # values [UnicodeNode|FormattedValueNode] Substrings of the f-string - # - type = unicode_type - is_temp = True - - subexprs = ['values'] - - def analyse_types(self, env): - self.values = [v.analyse_types(env).coerce_to_pyobject(env) for v in self.values] - return self - - def may_be_none(self): - # PyUnicode_Join() always returns a Unicode string or raises an exception - return False - - def generate_evaluation_code(self, code): - code.mark_pos(self.pos) - num_items = len(self.values) - list_var = code.funcstate.allocate_temp(py_object_type, manage_ref=True) - ulength_var = code.funcstate.allocate_temp(PyrexTypes.c_py_ssize_t_type, manage_ref=False) - max_char_var = code.funcstate.allocate_temp(PyrexTypes.c_py_ucs4_type, manage_ref=False) - - code.putln('%s = PyTuple_New(%s); %s' % ( - list_var, - num_items, - code.error_goto_if_null(list_var, self.pos))) - code.put_gotref(list_var) - code.putln("%s = 0;" % ulength_var) - code.putln("%s = 127;" % max_char_var) # at least ASCII character range - - for i, node in enumerate(self.values): - node.generate_evaluation_code(code) - node.make_owned_reference(code) - - ulength = "__Pyx_PyUnicode_GET_LENGTH(%s)" % node.py_result() - max_char_value = "__Pyx_PyUnicode_MAX_CHAR_VALUE(%s)" % node.py_result() - is_ascii = False - if isinstance(node, UnicodeNode): - try: +# F-strings +# +#------------------------------------------------------------------- + + +class JoinedStrNode(ExprNode): + # F-strings + # + # values [UnicodeNode|FormattedValueNode] Substrings of the f-string + # + type = unicode_type + is_temp = True + + subexprs = ['values'] + + def analyse_types(self, env): + self.values = [v.analyse_types(env).coerce_to_pyobject(env) for v in self.values] + return self + + def may_be_none(self): + # PyUnicode_Join() always returns a Unicode string or raises an exception + return False + + def generate_evaluation_code(self, code): + code.mark_pos(self.pos) + num_items = len(self.values) + list_var = code.funcstate.allocate_temp(py_object_type, manage_ref=True) + ulength_var = code.funcstate.allocate_temp(PyrexTypes.c_py_ssize_t_type, manage_ref=False) + max_char_var = code.funcstate.allocate_temp(PyrexTypes.c_py_ucs4_type, manage_ref=False) + + code.putln('%s = PyTuple_New(%s); %s' % ( + list_var, + num_items, + code.error_goto_if_null(list_var, self.pos))) + code.put_gotref(list_var) + code.putln("%s = 0;" % ulength_var) + code.putln("%s = 127;" % max_char_var) # at least ASCII character range + + for i, node in enumerate(self.values): + node.generate_evaluation_code(code) + node.make_owned_reference(code) + + ulength = "__Pyx_PyUnicode_GET_LENGTH(%s)" % node.py_result() + max_char_value = "__Pyx_PyUnicode_MAX_CHAR_VALUE(%s)" % node.py_result() + is_ascii = False + if isinstance(node, UnicodeNode): + try: # most strings will be ASCII or at least Latin-1 - node.value.encode('iso8859-1') - max_char_value = '255' - node.value.encode('us-ascii') - is_ascii = True - except UnicodeEncodeError: + node.value.encode('iso8859-1') + max_char_value = '255' + node.value.encode('us-ascii') + is_ascii = True + except UnicodeEncodeError: if max_char_value != '255': # not ISO8859-1 => check BMP limit max_char = max(map(ord, node.value)) @@ -3191,133 +3191,133 @@ class JoinedStrNode(ExprNode): # not really worth implementing a check for surrogate pairs here # drawback: C code can differ when generating on Py2 with 2-byte Unicode pass - else: - ulength = str(len(node.value)) - elif isinstance(node, FormattedValueNode) and node.value.type.is_numeric: - is_ascii = True # formatted C numbers are always ASCII - - if not is_ascii: - code.putln("%s = (%s > %s) ? %s : %s;" % ( - max_char_var, max_char_value, max_char_var, max_char_value, max_char_var)) - code.putln("%s += %s;" % (ulength_var, ulength)) - - code.put_giveref(node.py_result()) - code.putln('PyTuple_SET_ITEM(%s, %s, %s);' % (list_var, i, node.py_result())) - node.generate_post_assignment_code(code) - node.free_temps(code) - - code.mark_pos(self.pos) - self.allocate_temp_result(code) - code.globalstate.use_utility_code(UtilityCode.load_cached("JoinPyUnicode", "StringTools.c")) - code.putln('%s = __Pyx_PyUnicode_Join(%s, %d, %s, %s); %s' % ( - self.result(), - list_var, - num_items, - ulength_var, - max_char_var, - code.error_goto_if_null(self.py_result(), self.pos))) - code.put_gotref(self.py_result()) - - code.put_decref_clear(list_var, py_object_type) - code.funcstate.release_temp(list_var) - code.funcstate.release_temp(ulength_var) - code.funcstate.release_temp(max_char_var) - - -class FormattedValueNode(ExprNode): - # {}-delimited portions of an f-string - # - # value ExprNode The expression itself + else: + ulength = str(len(node.value)) + elif isinstance(node, FormattedValueNode) and node.value.type.is_numeric: + is_ascii = True # formatted C numbers are always ASCII + + if not is_ascii: + code.putln("%s = (%s > %s) ? %s : %s;" % ( + max_char_var, max_char_value, max_char_var, max_char_value, max_char_var)) + code.putln("%s += %s;" % (ulength_var, ulength)) + + code.put_giveref(node.py_result()) + code.putln('PyTuple_SET_ITEM(%s, %s, %s);' % (list_var, i, node.py_result())) + node.generate_post_assignment_code(code) + node.free_temps(code) + + code.mark_pos(self.pos) + self.allocate_temp_result(code) + code.globalstate.use_utility_code(UtilityCode.load_cached("JoinPyUnicode", "StringTools.c")) + code.putln('%s = __Pyx_PyUnicode_Join(%s, %d, %s, %s); %s' % ( + self.result(), + list_var, + num_items, + ulength_var, + max_char_var, + code.error_goto_if_null(self.py_result(), self.pos))) + code.put_gotref(self.py_result()) + + code.put_decref_clear(list_var, py_object_type) + code.funcstate.release_temp(list_var) + code.funcstate.release_temp(ulength_var) + code.funcstate.release_temp(max_char_var) + + +class FormattedValueNode(ExprNode): + # {}-delimited portions of an f-string + # + # value ExprNode The expression itself # conversion_char str or None Type conversion (!s, !r, !a, or none, or 'd' for integer conversion) - # format_spec JoinedStrNode or None Format string passed to __format__ - # c_format_spec str or None If not None, formatting can be done at the C level - - subexprs = ['value', 'format_spec'] - - type = unicode_type - is_temp = True - c_format_spec = None - - find_conversion_func = { - 's': 'PyObject_Unicode', - 'r': 'PyObject_Repr', - 'a': 'PyObject_ASCII', # NOTE: mapped to PyObject_Repr() in Py2 + # format_spec JoinedStrNode or None Format string passed to __format__ + # c_format_spec str or None If not None, formatting can be done at the C level + + subexprs = ['value', 'format_spec'] + + type = unicode_type + is_temp = True + c_format_spec = None + + find_conversion_func = { + 's': 'PyObject_Unicode', + 'r': 'PyObject_Repr', + 'a': 'PyObject_ASCII', # NOTE: mapped to PyObject_Repr() in Py2 'd': '__Pyx_PyNumber_IntOrLong', # NOTE: internal mapping for '%d' formatting - }.get - - def may_be_none(self): - # PyObject_Format() always returns a Unicode string or raises an exception - return False - - def analyse_types(self, env): - self.value = self.value.analyse_types(env) - if not self.format_spec or self.format_spec.is_string_literal: - c_format_spec = self.format_spec.value if self.format_spec else self.value.type.default_format_spec - if self.value.type.can_coerce_to_pystring(env, format_spec=c_format_spec): - self.c_format_spec = c_format_spec - - if self.format_spec: - self.format_spec = self.format_spec.analyse_types(env).coerce_to_pyobject(env) - if self.c_format_spec is None: - self.value = self.value.coerce_to_pyobject(env) + }.get + + def may_be_none(self): + # PyObject_Format() always returns a Unicode string or raises an exception + return False + + def analyse_types(self, env): + self.value = self.value.analyse_types(env) + if not self.format_spec or self.format_spec.is_string_literal: + c_format_spec = self.format_spec.value if self.format_spec else self.value.type.default_format_spec + if self.value.type.can_coerce_to_pystring(env, format_spec=c_format_spec): + self.c_format_spec = c_format_spec + + if self.format_spec: + self.format_spec = self.format_spec.analyse_types(env).coerce_to_pyobject(env) + if self.c_format_spec is None: + self.value = self.value.coerce_to_pyobject(env) if not self.format_spec and (not self.conversion_char or self.conversion_char == 's'): - if self.value.type is unicode_type and not self.value.may_be_none(): - # value is definitely a unicode string and we don't format it any special - return self.value - return self - - def generate_result_code(self, code): - if self.c_format_spec is not None and not self.value.type.is_pyobject: - convert_func_call = self.value.type.convert_to_pystring( - self.value.result(), code, self.c_format_spec) - code.putln("%s = %s; %s" % ( - self.result(), - convert_func_call, - code.error_goto_if_null(self.result(), self.pos))) - code.put_gotref(self.py_result()) - return - - value_result = self.value.py_result() - value_is_unicode = self.value.type is unicode_type and not self.value.may_be_none() - if self.format_spec: - format_func = '__Pyx_PyObject_Format' - format_spec = self.format_spec.py_result() - else: - # common case: expect simple Unicode pass-through if no format spec - format_func = '__Pyx_PyObject_FormatSimple' - # passing a Unicode format string in Py2 forces PyObject_Format() to also return a Unicode string - format_spec = Naming.empty_unicode - - conversion_char = self.conversion_char - if conversion_char == 's' and value_is_unicode: - # no need to pipe unicode strings through str() - conversion_char = None - - if conversion_char: - fn = self.find_conversion_func(conversion_char) - assert fn is not None, "invalid conversion character found: '%s'" % conversion_char - value_result = '%s(%s)' % (fn, value_result) - code.globalstate.use_utility_code( - UtilityCode.load_cached("PyObjectFormatAndDecref", "StringTools.c")) - format_func += 'AndDecref' - elif self.format_spec: - code.globalstate.use_utility_code( - UtilityCode.load_cached("PyObjectFormat", "StringTools.c")) - else: - code.globalstate.use_utility_code( - UtilityCode.load_cached("PyObjectFormatSimple", "StringTools.c")) - - code.putln("%s = %s(%s, %s); %s" % ( - self.result(), - format_func, - value_result, - format_spec, - code.error_goto_if_null(self.result(), self.pos))) - code.put_gotref(self.py_result()) - - -#------------------------------------------------------------------- -# + if self.value.type is unicode_type and not self.value.may_be_none(): + # value is definitely a unicode string and we don't format it any special + return self.value + return self + + def generate_result_code(self, code): + if self.c_format_spec is not None and not self.value.type.is_pyobject: + convert_func_call = self.value.type.convert_to_pystring( + self.value.result(), code, self.c_format_spec) + code.putln("%s = %s; %s" % ( + self.result(), + convert_func_call, + code.error_goto_if_null(self.result(), self.pos))) + code.put_gotref(self.py_result()) + return + + value_result = self.value.py_result() + value_is_unicode = self.value.type is unicode_type and not self.value.may_be_none() + if self.format_spec: + format_func = '__Pyx_PyObject_Format' + format_spec = self.format_spec.py_result() + else: + # common case: expect simple Unicode pass-through if no format spec + format_func = '__Pyx_PyObject_FormatSimple' + # passing a Unicode format string in Py2 forces PyObject_Format() to also return a Unicode string + format_spec = Naming.empty_unicode + + conversion_char = self.conversion_char + if conversion_char == 's' and value_is_unicode: + # no need to pipe unicode strings through str() + conversion_char = None + + if conversion_char: + fn = self.find_conversion_func(conversion_char) + assert fn is not None, "invalid conversion character found: '%s'" % conversion_char + value_result = '%s(%s)' % (fn, value_result) + code.globalstate.use_utility_code( + UtilityCode.load_cached("PyObjectFormatAndDecref", "StringTools.c")) + format_func += 'AndDecref' + elif self.format_spec: + code.globalstate.use_utility_code( + UtilityCode.load_cached("PyObjectFormat", "StringTools.c")) + else: + code.globalstate.use_utility_code( + UtilityCode.load_cached("PyObjectFormatSimple", "StringTools.c")) + + code.putln("%s = %s(%s, %s); %s" % ( + self.result(), + format_func, + value_result, + format_spec, + code.error_goto_if_null(self.result(), self.pos))) + code.put_gotref(self.py_result()) + + +#------------------------------------------------------------------- +# # Parallel nodes (cython.parallel.thread(savailable|id)) # #------------------------------------------------------------------- @@ -3380,38 +3380,38 @@ class ParallelThreadIdNode(AtomicExprNode): #, Nodes.ParallelNode): # #------------------------------------------------------------------- - -class _IndexingBaseNode(ExprNode): - # Base class for indexing nodes. - # - # base ExprNode the value being indexed - - def is_ephemeral(self): - # in most cases, indexing will return a safe reference to an object in a container, - # so we consider the result safe if the base object is - return self.base.is_ephemeral() or self.base.type in ( + +class _IndexingBaseNode(ExprNode): + # Base class for indexing nodes. + # + # base ExprNode the value being indexed + + def is_ephemeral(self): + # in most cases, indexing will return a safe reference to an object in a container, + # so we consider the result safe if the base object is + return self.base.is_ephemeral() or self.base.type in ( basestring_type, str_type, bytes_type, bytearray_type, unicode_type) - - def check_const_addr(self): - return self.base.check_const_addr() and self.index.check_const() - - def is_lvalue(self): - # NOTE: references currently have both is_reference and is_ptr - # set. Since pointers and references have different lvalue - # rules, we must be careful to separate the two. - if self.type.is_reference: - if self.type.ref_base_type.is_array: - # fixed-sized arrays aren't l-values - return False - elif self.type.is_ptr: - # non-const pointers can always be reassigned - return True - # Just about everything else returned by the index operator - # can be an lvalue. - return True - - -class IndexNode(_IndexingBaseNode): + + def check_const_addr(self): + return self.base.check_const_addr() and self.index.check_const() + + def is_lvalue(self): + # NOTE: references currently have both is_reference and is_ptr + # set. Since pointers and references have different lvalue + # rules, we must be careful to separate the two. + if self.type.is_reference: + if self.type.ref_base_type.is_array: + # fixed-sized arrays aren't l-values + return False + elif self.type.is_ptr: + # non-const pointers can always be reassigned + return True + # Just about everything else returned by the index operator + # can be an lvalue. + return True + + +class IndexNode(_IndexingBaseNode): # Sequence indexing. # # base ExprNode @@ -3421,21 +3421,21 @@ class IndexNode(_IndexingBaseNode): # is_fused_index boolean Whether the index is used to specialize a # c(p)def function - subexprs = ['base', 'index'] + subexprs = ['base', 'index'] type_indices = None is_subscript = True is_fused_index = False def calculate_constant_result(self): - self.constant_result = self.base.constant_result[self.index.constant_result] + self.constant_result = self.base.constant_result[self.index.constant_result] def compile_time_value(self, denv): base = self.base.compile_time_value(denv) index = self.index.compile_time_value(denv) try: return base[index] - except Exception as e: + except Exception as e: self.compile_time_value_error(e) def is_simple(self): @@ -3467,26 +3467,26 @@ class IndexNode(_IndexingBaseNode): else: template_values = [self.index] type_node = Nodes.TemplatedTypeNode( - pos=self.pos, - positional_args=template_values, - keyword_args=None) - return type_node.analyse(env, base_type=base_type) - elif self.index.is_slice or self.index.is_sequence_constructor: - # memory view - from . import MemoryView - env.use_utility_code(MemoryView.view_utility_code) - axes = [self.index] if self.index.is_slice else list(self.index.args) - return PyrexTypes.MemoryViewSliceType(base_type, MemoryView.get_axes_specs(env, axes)) + pos=self.pos, + positional_args=template_values, + keyword_args=None) + return type_node.analyse(env, base_type=base_type) + elif self.index.is_slice or self.index.is_sequence_constructor: + # memory view + from . import MemoryView + env.use_utility_code(MemoryView.view_utility_code) + axes = [self.index] if self.index.is_slice else list(self.index.args) + return PyrexTypes.MemoryViewSliceType(base_type, MemoryView.get_axes_specs(env, axes)) else: - # C array + # C array index = self.index.compile_time_value(env) if index is not None: - try: - index = int(index) - except (ValueError, TypeError): - pass - else: - return PyrexTypes.CArrayType(base_type, index) + try: + index = int(index) + except (ValueError, TypeError): + pass + else: + return PyrexTypes.CArrayType(base_type, index) error(self.pos, "Array size must be a compile time constant") return None @@ -3495,7 +3495,7 @@ class IndexNode(_IndexingBaseNode): def infer_type(self, env): base_type = self.base.infer_type(env) - if self.index.is_slice: + if self.index.is_slice: # slicing! if base_type.is_string: # sliced C strings must coerce to Python @@ -3542,13 +3542,13 @@ class IndexNode(_IndexingBaseNode): return item_type elif base_type.is_ptr or base_type.is_array: return base_type.base_type - elif base_type.is_ctuple and isinstance(self.index, IntNode): - if self.index.has_constant_result(): - index = self.index.constant_result - if index < 0: - index += base_type.size - if 0 <= index < base_type.size: - return base_type.components[index] + elif base_type.is_ctuple and isinstance(self.index, IntNode): + if self.index.has_constant_result(): + index = self.index.constant_result + if index < 0: + index += base_type.size + if 0 <= index < base_type.size: + return base_type.components[index] if base_type.is_cpp_class: class FakeOperand: @@ -3581,7 +3581,7 @@ class IndexNode(_IndexingBaseNode): node = self.analyse_base_and_index_types(env, setting=True) if node.type.is_const: error(self.pos, "Assignment to const dereference") - if node is self and not node.is_lvalue(): + if node is self and not node.is_lvalue(): error(self.pos, "Assignment to non-lvalue of type '%s'" % node.type) return node @@ -3599,7 +3599,7 @@ class IndexNode(_IndexingBaseNode): self.type = PyrexTypes.error_type return self - is_slice = self.index.is_slice + is_slice = self.index.is_slice if not env.directives['wraparound']: if is_slice: check_negative_indices(self.index.start, self.index.stop) @@ -3616,16 +3616,16 @@ class IndexNode(_IndexingBaseNode): if self.base.type.is_string or not (self.base.type.is_ptr or self.base.type.is_array): self.base = self.base.coerce_to_pyobject(env) - replacement_node = self.analyse_as_buffer_operation(env, getting) - if replacement_node is not None: - return replacement_node + replacement_node = self.analyse_as_buffer_operation(env, getting) + if replacement_node is not None: + return replacement_node self.nogil = env.nogil - base_type = self.base.type + base_type = self.base.type - if not base_type.is_cfunction: - self.index = self.index.analyse_types(env) - self.original_index_type = self.index.type + if not base_type.is_cfunction: + self.index = self.index.analyse_types(env) + self.original_index_type = self.index.type if base_type.is_unicode_char: # we infer Py_UNICODE/Py_UCS4 for unicode strings in some @@ -3637,26 +3637,26 @@ class IndexNode(_IndexingBaseNode): return self.base self.base = self.base.coerce_to_pyobject(env) base_type = self.base.type - - if base_type.is_pyobject: - return self.analyse_as_pyobject(env, is_slice, getting, setting) - elif base_type.is_ptr or base_type.is_array: - return self.analyse_as_c_array(env, is_slice) - elif base_type.is_cpp_class: - return self.analyse_as_cpp(env, setting) - elif base_type.is_cfunction: - return self.analyse_as_c_function(env) - elif base_type.is_ctuple: - return self.analyse_as_c_tuple(env, getting, setting) - else: - error(self.pos, - "Attempting to index non-array type '%s'" % - base_type) - self.type = PyrexTypes.error_type - return self - - def analyse_as_pyobject(self, env, is_slice, getting, setting): - base_type = self.base.type + + if base_type.is_pyobject: + return self.analyse_as_pyobject(env, is_slice, getting, setting) + elif base_type.is_ptr or base_type.is_array: + return self.analyse_as_c_array(env, is_slice) + elif base_type.is_cpp_class: + return self.analyse_as_cpp(env, setting) + elif base_type.is_cfunction: + return self.analyse_as_c_function(env) + elif base_type.is_ctuple: + return self.analyse_as_c_tuple(env, getting, setting) + else: + error(self.pos, + "Attempting to index non-array type '%s'" % + base_type) + self.type = PyrexTypes.error_type + return self + + def analyse_as_pyobject(self, env, is_slice, getting, setting): + base_type = self.base.type if self.index.type.is_unicode_char and base_type is not dict_type: # TODO: eventually fold into case below and remove warning, once people have adapted their code warning(self.pos, @@ -3665,139 +3665,139 @@ class IndexNode(_IndexingBaseNode): self.index = self.index.coerce_to_pyobject(env) self.is_temp = 1 elif self.index.type.is_int and base_type is not dict_type: - if (getting - and (base_type in (list_type, tuple_type, bytearray_type)) - and (not self.index.type.signed - or not env.directives['wraparound'] - or (isinstance(self.index, IntNode) and - self.index.has_constant_result() and self.index.constant_result >= 0)) - and not env.directives['boundscheck']): - self.is_temp = 0 + if (getting + and (base_type in (list_type, tuple_type, bytearray_type)) + and (not self.index.type.signed + or not env.directives['wraparound'] + or (isinstance(self.index, IntNode) and + self.index.has_constant_result() and self.index.constant_result >= 0)) + and not env.directives['boundscheck']): + self.is_temp = 0 + else: + self.is_temp = 1 + self.index = self.index.coerce_to(PyrexTypes.c_py_ssize_t_type, env).coerce_to_simple(env) + self.original_index_type.create_to_py_utility_code(env) + else: + self.index = self.index.coerce_to_pyobject(env) + self.is_temp = 1 + + if self.index.type.is_int and base_type is unicode_type: + # Py_UNICODE/Py_UCS4 will automatically coerce to a unicode string + # if required, so this is fast and safe + self.type = PyrexTypes.c_py_ucs4_type + elif self.index.type.is_int and base_type is bytearray_type: + if setting: + self.type = PyrexTypes.c_uchar_type else: - self.is_temp = 1 - self.index = self.index.coerce_to(PyrexTypes.c_py_ssize_t_type, env).coerce_to_simple(env) - self.original_index_type.create_to_py_utility_code(env) - else: - self.index = self.index.coerce_to_pyobject(env) - self.is_temp = 1 - - if self.index.type.is_int and base_type is unicode_type: - # Py_UNICODE/Py_UCS4 will automatically coerce to a unicode string - # if required, so this is fast and safe - self.type = PyrexTypes.c_py_ucs4_type - elif self.index.type.is_int and base_type is bytearray_type: - if setting: - self.type = PyrexTypes.c_uchar_type - else: - # not using 'uchar' to enable fast and safe error reporting as '-1' - self.type = PyrexTypes.c_int_type + # not using 'uchar' to enable fast and safe error reporting as '-1' + self.type = PyrexTypes.c_int_type elif is_slice and base_type in (bytes_type, bytearray_type, str_type, unicode_type, list_type, tuple_type): - self.type = base_type - else: - item_type = None - if base_type in (list_type, tuple_type) and self.index.type.is_int: - item_type = infer_sequence_item_type( - env, self.base, self.index, seq_type=base_type) - if item_type is None: - item_type = py_object_type - self.type = item_type - if base_type in (list_type, tuple_type, dict_type): - # do the None check explicitly (not in a helper) to allow optimising it away - self.base = self.base.as_none_safe_node("'NoneType' object is not subscriptable") - + self.type = base_type + else: + item_type = None + if base_type in (list_type, tuple_type) and self.index.type.is_int: + item_type = infer_sequence_item_type( + env, self.base, self.index, seq_type=base_type) + if item_type is None: + item_type = py_object_type + self.type = item_type + if base_type in (list_type, tuple_type, dict_type): + # do the None check explicitly (not in a helper) to allow optimising it away + self.base = self.base.as_none_safe_node("'NoneType' object is not subscriptable") + self.wrap_in_nonecheck_node(env, getting) return self - def analyse_as_c_array(self, env, is_slice): - base_type = self.base.type - self.type = base_type.base_type - if is_slice: - self.type = base_type - elif self.index.type.is_pyobject: - self.index = self.index.coerce_to(PyrexTypes.c_py_ssize_t_type, env) - elif not self.index.type.is_int: - error(self.pos, "Invalid index type '%s'" % self.index.type) - return self - - def analyse_as_cpp(self, env, setting): - base_type = self.base.type - function = env.lookup_operator("[]", [self.base, self.index]) - if function is None: - error(self.pos, "Indexing '%s' not supported for index type '%s'" % (base_type, self.index.type)) - self.type = PyrexTypes.error_type - self.result_code = "<error>" - return self - func_type = function.type - if func_type.is_ptr: - func_type = func_type.base_type - self.exception_check = func_type.exception_check - self.exception_value = func_type.exception_value - if self.exception_check: - if not setting: - self.is_temp = True - if self.exception_value is None: - env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp")) - self.index = self.index.coerce_to(func_type.args[0].type, env) - self.type = func_type.return_type - if setting and not func_type.return_type.is_reference: - error(self.pos, "Can't set non-reference result '%s'" % self.type) - return self - - def analyse_as_c_function(self, env): - base_type = self.base.type - if base_type.is_fused: - self.parse_indexed_fused_cdef(env) - else: - self.type_indices = self.parse_index_as_types(env) - self.index = None # FIXME: use a dedicated Node class instead of generic IndexNode - if base_type.templates is None: - error(self.pos, "Can only parameterize template functions.") - self.type = error_type + def analyse_as_c_array(self, env, is_slice): + base_type = self.base.type + self.type = base_type.base_type + if is_slice: + self.type = base_type + elif self.index.type.is_pyobject: + self.index = self.index.coerce_to(PyrexTypes.c_py_ssize_t_type, env) + elif not self.index.type.is_int: + error(self.pos, "Invalid index type '%s'" % self.index.type) + return self + + def analyse_as_cpp(self, env, setting): + base_type = self.base.type + function = env.lookup_operator("[]", [self.base, self.index]) + if function is None: + error(self.pos, "Indexing '%s' not supported for index type '%s'" % (base_type, self.index.type)) + self.type = PyrexTypes.error_type + self.result_code = "<error>" + return self + func_type = function.type + if func_type.is_ptr: + func_type = func_type.base_type + self.exception_check = func_type.exception_check + self.exception_value = func_type.exception_value + if self.exception_check: + if not setting: + self.is_temp = True + if self.exception_value is None: + env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp")) + self.index = self.index.coerce_to(func_type.args[0].type, env) + self.type = func_type.return_type + if setting and not func_type.return_type.is_reference: + error(self.pos, "Can't set non-reference result '%s'" % self.type) + return self + + def analyse_as_c_function(self, env): + base_type = self.base.type + if base_type.is_fused: + self.parse_indexed_fused_cdef(env) + else: + self.type_indices = self.parse_index_as_types(env) + self.index = None # FIXME: use a dedicated Node class instead of generic IndexNode + if base_type.templates is None: + error(self.pos, "Can only parameterize template functions.") + self.type = error_type elif self.type_indices is None: # Error recorded earlier. self.type = error_type - elif len(base_type.templates) != len(self.type_indices): - error(self.pos, "Wrong number of template arguments: expected %s, got %s" % ( - (len(base_type.templates), len(self.type_indices)))) - self.type = error_type + elif len(base_type.templates) != len(self.type_indices): + error(self.pos, "Wrong number of template arguments: expected %s, got %s" % ( + (len(base_type.templates), len(self.type_indices)))) + self.type = error_type + else: + self.type = base_type.specialize(dict(zip(base_type.templates, self.type_indices))) + # FIXME: use a dedicated Node class instead of generic IndexNode + return self + + def analyse_as_c_tuple(self, env, getting, setting): + base_type = self.base.type + if isinstance(self.index, IntNode) and self.index.has_constant_result(): + index = self.index.constant_result + if -base_type.size <= index < base_type.size: + if index < 0: + index += base_type.size + self.type = base_type.components[index] else: - self.type = base_type.specialize(dict(zip(base_type.templates, self.type_indices))) - # FIXME: use a dedicated Node class instead of generic IndexNode - return self - - def analyse_as_c_tuple(self, env, getting, setting): - base_type = self.base.type - if isinstance(self.index, IntNode) and self.index.has_constant_result(): - index = self.index.constant_result - if -base_type.size <= index < base_type.size: - if index < 0: - index += base_type.size - self.type = base_type.components[index] - else: - error(self.pos, - "Index %s out of bounds for '%s'" % - (index, base_type)) - self.type = PyrexTypes.error_type - return self - else: - self.base = self.base.coerce_to_pyobject(env) - return self.analyse_base_and_index_types(env, getting=getting, setting=setting, analyse_base=False) - - def analyse_as_buffer_operation(self, env, getting): - """ - Analyse buffer indexing and memoryview indexing/slicing - """ - if isinstance(self.index, TupleNode): - indices = self.index.args - else: - indices = [self.index] + error(self.pos, + "Index %s out of bounds for '%s'" % + (index, base_type)) + self.type = PyrexTypes.error_type + return self + else: + self.base = self.base.coerce_to_pyobject(env) + return self.analyse_base_and_index_types(env, getting=getting, setting=setting, analyse_base=False) + + def analyse_as_buffer_operation(self, env, getting): + """ + Analyse buffer indexing and memoryview indexing/slicing + """ + if isinstance(self.index, TupleNode): + indices = self.index.args + else: + indices = [self.index] base = self.base base_type = base.type - replacement_node = None - if base_type.is_memoryviewslice: - # memoryviewslice indexing or slicing - from . import MemoryView + replacement_node = None + if base_type.is_memoryviewslice: + # memoryviewslice indexing or slicing + from . import MemoryView if base.is_memview_slice: # For memory views, "view[i][j]" is the same as "view[i, j]" => use the latter for speed. merged_indices = base.merged_indices(indices) @@ -3805,10 +3805,10 @@ class IndexNode(_IndexingBaseNode): base = base.base base_type = base.type indices = merged_indices - have_slices, indices, newaxes = MemoryView.unellipsify(indices, base_type.ndim) - if have_slices: + have_slices, indices, newaxes = MemoryView.unellipsify(indices, base_type.ndim) + if have_slices: replacement_node = MemoryViewSliceNode(self.pos, indices=indices, base=base) - else: + else: replacement_node = MemoryViewIndexNode(self.pos, indices=indices, base=base) elif base_type.is_buffer or base_type.is_pythran_expr: if base_type.is_pythran_expr or len(indices) == base_type.ndim: @@ -3831,16 +3831,16 @@ class IndexNode(_IndexingBaseNode): replacement_node = BufferIndexNode(self.pos, indices=indices, base=base) # On cloning, indices is cloned. Otherwise, unpack index into indices. assert not isinstance(self.index, CloneNode) - - if replacement_node is not None: - replacement_node = replacement_node.analyse_types(env, getting) - return replacement_node - - def wrap_in_nonecheck_node(self, env, getting): - if not env.directives['nonecheck'] or not self.base.may_be_none(): - return - self.base = self.base.as_none_safe_node("'NoneType' object is not subscriptable") - + + if replacement_node is not None: + replacement_node = replacement_node.analyse_types(env, getting) + return replacement_node + + def wrap_in_nonecheck_node(self, env, getting): + if not env.directives['nonecheck'] or not self.base.may_be_none(): + return + self.base = self.base.as_none_safe_node("'NoneType' object is not subscriptable") + def parse_index_as_types(self, env, required=True): if isinstance(self.index, TupleNode): indices = self.index.args @@ -3949,7 +3949,7 @@ class IndexNode(_IndexingBaseNode): gil_message = "Indexing Python object" def calculate_result_code(self): - if self.base.type in (list_type, tuple_type, bytearray_type): + if self.base.type in (list_type, tuple_type, bytearray_type): if self.base.type is list_type: index_code = "PyList_GET_ITEM(%s, %s)" elif self.base.type is tuple_type: @@ -3961,12 +3961,12 @@ class IndexNode(_IndexingBaseNode): elif self.base.type.is_cfunction: return "%s<%s>" % ( self.base.result(), - ",".join([param.empty_declaration_code() for param in self.type_indices])) - elif self.base.type.is_ctuple: - index = self.index.constant_result - if index < 0: - index += self.base.type.size - return "%s.f%s" % (self.base.result(), index) + ",".join([param.empty_declaration_code() for param in self.type_indices])) + elif self.base.type.is_ctuple: + index = self.index.constant_result + if index < 0: + index += self.base.type.size + return "%s.f%s" % (self.base.result(), index) else: if (self.type.is_ptr or self.type.is_array) and self.type == self.base.type: error(self.pos, "Invalid use of pointer slice") @@ -3980,11 +3980,11 @@ class IndexNode(_IndexingBaseNode): wraparound = ( bool(code.globalstate.directives['wraparound']) and self.original_index_type.signed and - not (isinstance(self.index.constant_result, _py_int_types) + not (isinstance(self.index.constant_result, _py_int_types) and self.index.constant_result >= 0)) boundscheck = bool(code.globalstate.directives['boundscheck']) return ", %s, %d, %s, %d, %d, %d" % ( - self.original_index_type.empty_declaration_code(), + self.original_index_type.empty_declaration_code(), self.original_index_type.signed and 1 or 0, self.original_index_type.to_py_function, is_list, wraparound, boundscheck) @@ -3992,24 +3992,24 @@ class IndexNode(_IndexingBaseNode): return "" def generate_result_code(self, code): - if not self.is_temp: - # all handled in self.calculate_result_code() - return + if not self.is_temp: + # all handled in self.calculate_result_code() + return utility_code = None - if self.type.is_pyobject: - error_value = 'NULL' - if self.index.type.is_int: - if self.base.type is list_type: - function = "__Pyx_GetItemInt_List" - elif self.base.type is tuple_type: - function = "__Pyx_GetItemInt_Tuple" + if self.type.is_pyobject: + error_value = 'NULL' + if self.index.type.is_int: + if self.base.type is list_type: + function = "__Pyx_GetItemInt_List" + elif self.base.type is tuple_type: + function = "__Pyx_GetItemInt_Tuple" else: - function = "__Pyx_GetItemInt" + function = "__Pyx_GetItemInt" utility_code = TempitaUtilityCode.load_cached("GetItemInt", "ObjectHandling.c") else: - if self.base.type is dict_type: - function = "__Pyx_PyDict_GetItem" + if self.base.type is dict_type: + function = "__Pyx_PyDict_GetItem" utility_code = UtilityCode.load_cached("DictGetItem", "ObjectHandling.c") elif self.base.type is py_object_type and self.index.type in (str_type, unicode_type): # obj[str] is probably doing a dict lookup @@ -4017,50 +4017,50 @@ class IndexNode(_IndexingBaseNode): utility_code = UtilityCode.load_cached("DictGetItem", "ObjectHandling.c") else: function = "__Pyx_PyObject_GetItem" - code.globalstate.use_utility_code( + code.globalstate.use_utility_code( TempitaUtilityCode.load_cached("GetItemInt", "ObjectHandling.c")) utility_code = UtilityCode.load_cached("ObjectGetItem", "ObjectHandling.c") - elif self.type.is_unicode_char and self.base.type is unicode_type: - assert self.index.type.is_int - function = "__Pyx_GetItemInt_Unicode" - error_value = '(Py_UCS4)-1' + elif self.type.is_unicode_char and self.base.type is unicode_type: + assert self.index.type.is_int + function = "__Pyx_GetItemInt_Unicode" + error_value = '(Py_UCS4)-1' utility_code = UtilityCode.load_cached("GetItemIntUnicode", "StringTools.c") - elif self.base.type is bytearray_type: - assert self.index.type.is_int - assert self.type.is_int - function = "__Pyx_GetItemInt_ByteArray" - error_value = '-1' + elif self.base.type is bytearray_type: + assert self.index.type.is_int + assert self.type.is_int + function = "__Pyx_GetItemInt_ByteArray" + error_value = '-1' utility_code = UtilityCode.load_cached("GetItemIntByteArray", "StringTools.c") - elif not (self.base.type.is_cpp_class and self.exception_check): - assert False, "unexpected type %s and base type %s for indexing" % ( - self.type, self.base.type) + elif not (self.base.type.is_cpp_class and self.exception_check): + assert False, "unexpected type %s and base type %s for indexing" % ( + self.type, self.base.type) if utility_code is not None: code.globalstate.use_utility_code(utility_code) - if self.index.type.is_int: - index_code = self.index.result() - else: - index_code = self.index.py_result() - - if self.base.type.is_cpp_class and self.exception_check: - translate_cpp_exception(code, self.pos, - "%s = %s[%s];" % (self.result(), self.base.result(), - self.index.result()), - self.result() if self.type.is_pyobject else None, - self.exception_value, self.in_nogil_context) - else: - error_check = '!%s' if error_value == 'NULL' else '%%s == %s' % error_value + if self.index.type.is_int: + index_code = self.index.result() + else: + index_code = self.index.py_result() + + if self.base.type.is_cpp_class and self.exception_check: + translate_cpp_exception(code, self.pos, + "%s = %s[%s];" % (self.result(), self.base.result(), + self.index.result()), + self.result() if self.type.is_pyobject else None, + self.exception_value, self.in_nogil_context) + else: + error_check = '!%s' if error_value == 'NULL' else '%%s == %s' % error_value code.putln( - "%s = %s(%s, %s%s); %s" % ( + "%s = %s(%s, %s%s); %s" % ( self.result(), function, self.base.py_result(), index_code, self.extra_index_params(code), - code.error_goto_if(error_check % self.result(), self.pos))) - if self.type.is_pyobject: - code.put_gotref(self.py_result()) + code.error_goto_if(error_check % self.result(), self.pos))) + if self.type.is_pyobject: + code.put_gotref(self.py_result()) def generate_setitem_code(self, value_code, code): if self.index.type.is_int: @@ -4086,46 +4086,46 @@ class IndexNode(_IndexingBaseNode): # (PyTuple_SetItem() is for creating new tuples from scratch). else: function = "PyObject_SetItem" - code.putln(code.error_goto_if_neg( - "%s(%s, %s, %s%s)" % ( + code.putln(code.error_goto_if_neg( + "%s(%s, %s, %s%s)" % ( function, self.base.py_result(), index_code, value_code, - self.extra_index_params(code)), - self.pos)) + self.extra_index_params(code)), + self.pos)) - def generate_assignment_code(self, rhs, code, overloaded_assignment=False, - exception_check=None, exception_value=None): - self.generate_subexpr_evaluation_code(code) + def generate_assignment_code(self, rhs, code, overloaded_assignment=False, + exception_check=None, exception_value=None): + self.generate_subexpr_evaluation_code(code) - if self.type.is_pyobject: + if self.type.is_pyobject: self.generate_setitem_code(rhs.py_result(), code) elif self.base.type is bytearray_type: value_code = self._check_byte_value(code, rhs) self.generate_setitem_code(value_code, code) - elif self.base.type.is_cpp_class and self.exception_check and self.exception_check == '+': - if overloaded_assignment and exception_check and \ - self.exception_value != exception_value: - # Handle the case that both the index operator and the assignment - # operator have a c++ exception handler and they are not the same. - translate_double_cpp_exception(code, self.pos, self.type, - self.result(), rhs.result(), self.exception_value, - exception_value, self.in_nogil_context) - else: - # Handle the case that only the index operator has a - # c++ exception handler, or that - # both exception handlers are the same. - translate_cpp_exception(code, self.pos, - "%s = %s;" % (self.result(), rhs.result()), - self.result() if self.type.is_pyobject else None, - self.exception_value, self.in_nogil_context) + elif self.base.type.is_cpp_class and self.exception_check and self.exception_check == '+': + if overloaded_assignment and exception_check and \ + self.exception_value != exception_value: + # Handle the case that both the index operator and the assignment + # operator have a c++ exception handler and they are not the same. + translate_double_cpp_exception(code, self.pos, self.type, + self.result(), rhs.result(), self.exception_value, + exception_value, self.in_nogil_context) + else: + # Handle the case that only the index operator has a + # c++ exception handler, or that + # both exception handlers are the same. + translate_cpp_exception(code, self.pos, + "%s = %s;" % (self.result(), rhs.result()), + self.result() if self.type.is_pyobject else None, + self.exception_value, self.in_nogil_context) else: code.putln( - "%s = %s;" % (self.result(), rhs.result())) + "%s = %s;" % (self.result(), rhs.result())) - self.generate_subexpr_disposal_code(code) - self.free_subexpr_temps(code) + self.generate_subexpr_disposal_code(code) + self.free_subexpr_temps(code) rhs.generate_disposal_code(code) rhs.free_temps(code) @@ -4179,101 +4179,101 @@ class IndexNode(_IndexingBaseNode): function = "PyDict_DelItem" else: function = "PyObject_DelItem" - code.putln(code.error_goto_if_neg( - "%s(%s, %s%s)" % ( + code.putln(code.error_goto_if_neg( + "%s(%s, %s%s)" % ( function, self.base.py_result(), index_code, - self.extra_index_params(code)), - self.pos)) + self.extra_index_params(code)), + self.pos)) self.generate_subexpr_disposal_code(code) self.free_subexpr_temps(code) - -class BufferIndexNode(_IndexingBaseNode): - """ - Indexing of buffers and memoryviews. This node is created during type - analysis from IndexNode and replaces it. - - Attributes: - base - base node being indexed - indices - list of indexing expressions - """ - - subexprs = ['base', 'indices'] - - is_buffer_access = True - - # Whether we're assigning to a buffer (in that case it needs to be writable) - writable_needed = False - + +class BufferIndexNode(_IndexingBaseNode): + """ + Indexing of buffers and memoryviews. This node is created during type + analysis from IndexNode and replaces it. + + Attributes: + base - base node being indexed + indices - list of indexing expressions + """ + + subexprs = ['base', 'indices'] + + is_buffer_access = True + + # Whether we're assigning to a buffer (in that case it needs to be writable) + writable_needed = False + # Any indexing temp variables that we need to clean up. index_temps = () - def analyse_target_types(self, env): - self.analyse_types(env, getting=False) - - def analyse_types(self, env, getting=True): - """ - Analyse types for buffer indexing only. Overridden by memoryview - indexing and slicing subclasses - """ - # self.indices are already analyzed + def analyse_target_types(self, env): + self.analyse_types(env, getting=False) + + def analyse_types(self, env, getting=True): + """ + Analyse types for buffer indexing only. Overridden by memoryview + indexing and slicing subclasses + """ + # self.indices are already analyzed if not self.base.is_name and not is_pythran_expr(self.base.type): - error(self.pos, "Can only index buffer variables") - self.type = error_type - return self - - if not getting: - if not self.base.entry.type.writable: - error(self.pos, "Writing to readonly buffer") - else: - self.writable_needed = True - if self.base.type.is_buffer: - self.base.entry.buffer_aux.writable_needed = True - - self.none_error_message = "'NoneType' object is not subscriptable" - self.analyse_buffer_index(env, getting) - self.wrap_in_nonecheck_node(env) - return self - - def analyse_buffer_index(self, env, getting): + error(self.pos, "Can only index buffer variables") + self.type = error_type + return self + + if not getting: + if not self.base.entry.type.writable: + error(self.pos, "Writing to readonly buffer") + else: + self.writable_needed = True + if self.base.type.is_buffer: + self.base.entry.buffer_aux.writable_needed = True + + self.none_error_message = "'NoneType' object is not subscriptable" + self.analyse_buffer_index(env, getting) + self.wrap_in_nonecheck_node(env) + return self + + def analyse_buffer_index(self, env, getting): if is_pythran_expr(self.base.type): index_with_type_list = [(idx, idx.type) for idx in self.indices] self.type = PythranExpr(pythran_indexing_type(self.base.type, index_with_type_list)) else: self.base = self.base.coerce_to_simple(env) self.type = self.base.type.dtype - self.buffer_type = self.base.type - + self.buffer_type = self.base.type + if getting and (self.type.is_pyobject or self.type.is_pythran_expr): - self.is_temp = True - - def analyse_assignment(self, rhs): - """ - Called by IndexNode when this node is assigned to, - with the rhs of the assignment - """ - - def wrap_in_nonecheck_node(self, env): - if not env.directives['nonecheck'] or not self.base.may_be_none(): - return - self.base = self.base.as_none_safe_node(self.none_error_message) - - def nogil_check(self, env): - if self.is_buffer_access or self.is_memview_index: - if self.type.is_pyobject: - error(self.pos, "Cannot access buffer with object dtype without gil") - self.type = error_type - - def calculate_result_code(self): - return "(*%s)" % self.buffer_ptr_code - + self.is_temp = True + + def analyse_assignment(self, rhs): + """ + Called by IndexNode when this node is assigned to, + with the rhs of the assignment + """ + + def wrap_in_nonecheck_node(self, env): + if not env.directives['nonecheck'] or not self.base.may_be_none(): + return + self.base = self.base.as_none_safe_node(self.none_error_message) + + def nogil_check(self, env): + if self.is_buffer_access or self.is_memview_index: + if self.type.is_pyobject: + error(self.pos, "Cannot access buffer with object dtype without gil") + self.type = error_type + + def calculate_result_code(self): + return "(*%s)" % self.buffer_ptr_code + def buffer_entry(self): base = self.base if self.base.is_nonecheck: base = base.arg - return base.type.get_entry(base) + return base.type.get_entry(base) def get_index_in_temp(self, code, ivar): ret = code.funcstate.allocate_temp( @@ -4285,15 +4285,15 @@ class BufferIndexNode(_IndexingBaseNode): return ret def buffer_lookup_code(self, code): - """ - ndarray[1, 2, 3] and memslice[1, 2, 3] - """ + """ + ndarray[1, 2, 3] and memslice[1, 2, 3] + """ if self.in_nogil_context: if self.is_buffer_access or self.is_memview_index: if code.globalstate.directives['boundscheck']: warning(self.pos, "Use boundscheck(False) for faster access", level=1) - # Assign indices to temps of at least (s)size_t to allow further index calculations. + # Assign indices to temps of at least (s)size_t to allow further index calculations. self.index_temps = index_temps = [self.get_index_in_temp(code,ivar) for ivar in self.indices] # Generate buffer access code using these temps @@ -4305,23 +4305,23 @@ class BufferIndexNode(_IndexingBaseNode): negative_indices = Buffer.buffer_defaults['negative_indices'] return buffer_entry, Buffer.put_buffer_lookup_code( - entry=buffer_entry, - index_signeds=[ivar.type.signed for ivar in self.indices], - index_cnames=index_temps, - directives=code.globalstate.directives, - pos=self.pos, code=code, - negative_indices=negative_indices, - in_nogil_context=self.in_nogil_context) - - def generate_assignment_code(self, rhs, code, overloaded_assignment=False): - self.generate_subexpr_evaluation_code(code) - self.generate_buffer_setitem_code(rhs, code) - self.generate_subexpr_disposal_code(code) - self.free_subexpr_temps(code) - rhs.generate_disposal_code(code) - rhs.free_temps(code) - - def generate_buffer_setitem_code(self, rhs, code, op=""): + entry=buffer_entry, + index_signeds=[ivar.type.signed for ivar in self.indices], + index_cnames=index_temps, + directives=code.globalstate.directives, + pos=self.pos, code=code, + negative_indices=negative_indices, + in_nogil_context=self.in_nogil_context) + + def generate_assignment_code(self, rhs, code, overloaded_assignment=False): + self.generate_subexpr_evaluation_code(code) + self.generate_buffer_setitem_code(rhs, code) + self.generate_subexpr_disposal_code(code) + self.free_subexpr_temps(code) + rhs.generate_disposal_code(code) + rhs.free_temps(code) + + def generate_buffer_setitem_code(self, rhs, code, op=""): base_type = self.base.type if is_pythran_expr(base_type) and is_pythran_supported_type(rhs.type): obj = code.funcstate.allocate_temp(PythranExpr(pythran_type(self.base.type)), manage_ref=False) @@ -4343,27 +4343,27 @@ class BufferIndexNode(_IndexingBaseNode): code.funcstate.release_temp(obj) return - # Used from generate_assignment_code and InPlaceAssignmentNode - buffer_entry, ptrexpr = self.buffer_lookup_code(code) - - if self.buffer_type.dtype.is_pyobject: - # Must manage refcounts. Decref what is already there - # and incref what we put in. - ptr = code.funcstate.allocate_temp(buffer_entry.buf_ptr_type, - manage_ref=False) - rhs_code = rhs.result() - code.putln("%s = %s;" % (ptr, ptrexpr)) - code.put_gotref("*%s" % ptr) - code.putln("__Pyx_INCREF(%s); __Pyx_DECREF(*%s);" % ( - rhs_code, ptr)) - code.putln("*%s %s= %s;" % (ptr, op, rhs_code)) - code.put_giveref("*%s" % ptr) - code.funcstate.release_temp(ptr) - else: - # Simple case - code.putln("*%s %s= %s;" % (ptrexpr, op, rhs.result())) - - def generate_result_code(self, code): + # Used from generate_assignment_code and InPlaceAssignmentNode + buffer_entry, ptrexpr = self.buffer_lookup_code(code) + + if self.buffer_type.dtype.is_pyobject: + # Must manage refcounts. Decref what is already there + # and incref what we put in. + ptr = code.funcstate.allocate_temp(buffer_entry.buf_ptr_type, + manage_ref=False) + rhs_code = rhs.result() + code.putln("%s = %s;" % (ptr, ptrexpr)) + code.put_gotref("*%s" % ptr) + code.putln("__Pyx_INCREF(%s); __Pyx_DECREF(*%s);" % ( + rhs_code, ptr)) + code.putln("*%s %s= %s;" % (ptr, op, rhs_code)) + code.put_giveref("*%s" % ptr) + code.funcstate.release_temp(ptr) + else: + # Simple case + code.putln("*%s %s= %s;" % (ptrexpr, op, rhs.result())) + + def generate_result_code(self, code): if is_pythran_expr(self.base.type): res = self.result() code.putln("__Pyx_call_destructor(%s);" % res) @@ -4373,187 +4373,187 @@ class BufferIndexNode(_IndexingBaseNode): self.base.pythran_result(), pythran_indexing_code(self.indices))) return - buffer_entry, self.buffer_ptr_code = self.buffer_lookup_code(code) - if self.type.is_pyobject: - # is_temp is True, so must pull out value and incref it. - # NOTE: object temporary results for nodes are declared - # as PyObject *, so we need a cast - code.putln("%s = (PyObject *) *%s;" % (self.result(), self.buffer_ptr_code)) - code.putln("__Pyx_INCREF((PyObject*)%s);" % self.result()) - + buffer_entry, self.buffer_ptr_code = self.buffer_lookup_code(code) + if self.type.is_pyobject: + # is_temp is True, so must pull out value and incref it. + # NOTE: object temporary results for nodes are declared + # as PyObject *, so we need a cast + code.putln("%s = (PyObject *) *%s;" % (self.result(), self.buffer_ptr_code)) + code.putln("__Pyx_INCREF((PyObject*)%s);" % self.result()) + def free_subexpr_temps(self, code): for temp in self.index_temps: code.funcstate.release_temp(temp) self.index_temps = () super(BufferIndexNode, self).free_subexpr_temps(code) - - -class MemoryViewIndexNode(BufferIndexNode): - - is_memview_index = True - is_buffer_access = False - warned_untyped_idx = False - - def analyse_types(self, env, getting=True): - # memoryviewslice indexing or slicing - from . import MemoryView - + + +class MemoryViewIndexNode(BufferIndexNode): + + is_memview_index = True + is_buffer_access = False + warned_untyped_idx = False + + def analyse_types(self, env, getting=True): + # memoryviewslice indexing or slicing + from . import MemoryView + self.is_pythran_mode = has_np_pythran(env) - indices = self.indices - have_slices, indices, newaxes = MemoryView.unellipsify(indices, self.base.type.ndim) - + indices = self.indices + have_slices, indices, newaxes = MemoryView.unellipsify(indices, self.base.type.ndim) + if not getting: self.writable_needed = True if self.base.is_name or self.base.is_attribute: self.base.entry.type.writable_needed = True - self.memslice_index = (not newaxes and len(indices) == self.base.type.ndim) - axes = [] - - index_type = PyrexTypes.c_py_ssize_t_type - new_indices = [] - - if len(indices) - len(newaxes) > self.base.type.ndim: - self.type = error_type - error(indices[self.base.type.ndim].pos, - "Too many indices specified for type %s" % self.base.type) - return self - - axis_idx = 0 - for i, index in enumerate(indices[:]): - index = index.analyse_types(env) - if index.is_none: - self.is_memview_slice = True - new_indices.append(index) - axes.append(('direct', 'strided')) - continue - - access, packing = self.base.type.axes[axis_idx] - axis_idx += 1 - - if index.is_slice: - self.is_memview_slice = True - if index.step.is_none: - axes.append((access, packing)) - else: - axes.append((access, 'strided')) - - # Coerce start, stop and step to temps of the right type - for attr in ('start', 'stop', 'step'): - value = getattr(index, attr) - if not value.is_none: - value = value.coerce_to(index_type, env) - #value = value.coerce_to_temp(env) - setattr(index, attr, value) - new_indices.append(value) - - elif index.type.is_int or index.type.is_pyobject: - if index.type.is_pyobject and not self.warned_untyped_idx: - warning(index.pos, "Index should be typed for more efficient access", level=2) - MemoryViewIndexNode.warned_untyped_idx = True - - self.is_memview_index = True - index = index.coerce_to(index_type, env) - indices[i] = index - new_indices.append(index) - - else: - self.type = error_type - error(index.pos, "Invalid index for memoryview specified, type %s" % index.type) - return self - - ### FIXME: replace by MemoryViewSliceNode if is_memview_slice ? - self.is_memview_index = self.is_memview_index and not self.is_memview_slice - self.indices = new_indices - # All indices with all start/stop/step for slices. - # We need to keep this around. - self.original_indices = indices - self.nogil = env.nogil - - self.analyse_operation(env, getting, axes) - self.wrap_in_nonecheck_node(env) - return self - - def analyse_operation(self, env, getting, axes): - self.none_error_message = "Cannot index None memoryview slice" - self.analyse_buffer_index(env, getting) - - def analyse_broadcast_operation(self, rhs): - """ - Support broadcasting for slice assignment. - E.g. - m_2d[...] = m_1d # or, - m_1d[...] = m_2d # if the leading dimension has extent 1 - """ - if self.type.is_memoryviewslice: - lhs = self - if lhs.is_memview_broadcast or rhs.is_memview_broadcast: - lhs.is_memview_broadcast = True - rhs.is_memview_broadcast = True - - def analyse_as_memview_scalar_assignment(self, rhs): - lhs = self.analyse_assignment(rhs) - if lhs: - rhs.is_memview_copy_assignment = lhs.is_memview_copy_assignment - return lhs - return self - - -class MemoryViewSliceNode(MemoryViewIndexNode): - - is_memview_slice = True - - # No-op slicing operation, this node will be replaced - is_ellipsis_noop = False - is_memview_scalar_assignment = False - is_memview_index = False - is_memview_broadcast = False - - def analyse_ellipsis_noop(self, env, getting): - """Slicing operations needing no evaluation, i.e. m[...] or m[:, :]""" - ### FIXME: replace directly - self.is_ellipsis_noop = all( - index.is_slice and index.start.is_none and index.stop.is_none and index.step.is_none - for index in self.indices) - - if self.is_ellipsis_noop: - self.type = self.base.type - - def analyse_operation(self, env, getting, axes): - from . import MemoryView - - if not getting: - self.is_memview_broadcast = True - self.none_error_message = "Cannot assign to None memoryview slice" - else: - self.none_error_message = "Cannot slice None memoryview slice" - - self.analyse_ellipsis_noop(env, getting) - if self.is_ellipsis_noop: - return - - self.index = None - self.is_temp = True - self.use_managed_ref = True - - if not MemoryView.validate_axes(self.pos, axes): - self.type = error_type - return - - self.type = PyrexTypes.MemoryViewSliceType(self.base.type.dtype, axes) - - if not (self.base.is_simple() or self.base.result_in_temp()): - self.base = self.base.coerce_to_temp(env) - - def analyse_assignment(self, rhs): - if not rhs.type.is_memoryviewslice and ( - self.type.dtype.assignable_from(rhs.type) or - rhs.type.is_pyobject): - # scalar assignment - return MemoryCopyScalar(self.pos, self) - else: - return MemoryCopySlice(self.pos, self) - + self.memslice_index = (not newaxes and len(indices) == self.base.type.ndim) + axes = [] + + index_type = PyrexTypes.c_py_ssize_t_type + new_indices = [] + + if len(indices) - len(newaxes) > self.base.type.ndim: + self.type = error_type + error(indices[self.base.type.ndim].pos, + "Too many indices specified for type %s" % self.base.type) + return self + + axis_idx = 0 + for i, index in enumerate(indices[:]): + index = index.analyse_types(env) + if index.is_none: + self.is_memview_slice = True + new_indices.append(index) + axes.append(('direct', 'strided')) + continue + + access, packing = self.base.type.axes[axis_idx] + axis_idx += 1 + + if index.is_slice: + self.is_memview_slice = True + if index.step.is_none: + axes.append((access, packing)) + else: + axes.append((access, 'strided')) + + # Coerce start, stop and step to temps of the right type + for attr in ('start', 'stop', 'step'): + value = getattr(index, attr) + if not value.is_none: + value = value.coerce_to(index_type, env) + #value = value.coerce_to_temp(env) + setattr(index, attr, value) + new_indices.append(value) + + elif index.type.is_int or index.type.is_pyobject: + if index.type.is_pyobject and not self.warned_untyped_idx: + warning(index.pos, "Index should be typed for more efficient access", level=2) + MemoryViewIndexNode.warned_untyped_idx = True + + self.is_memview_index = True + index = index.coerce_to(index_type, env) + indices[i] = index + new_indices.append(index) + + else: + self.type = error_type + error(index.pos, "Invalid index for memoryview specified, type %s" % index.type) + return self + + ### FIXME: replace by MemoryViewSliceNode if is_memview_slice ? + self.is_memview_index = self.is_memview_index and not self.is_memview_slice + self.indices = new_indices + # All indices with all start/stop/step for slices. + # We need to keep this around. + self.original_indices = indices + self.nogil = env.nogil + + self.analyse_operation(env, getting, axes) + self.wrap_in_nonecheck_node(env) + return self + + def analyse_operation(self, env, getting, axes): + self.none_error_message = "Cannot index None memoryview slice" + self.analyse_buffer_index(env, getting) + + def analyse_broadcast_operation(self, rhs): + """ + Support broadcasting for slice assignment. + E.g. + m_2d[...] = m_1d # or, + m_1d[...] = m_2d # if the leading dimension has extent 1 + """ + if self.type.is_memoryviewslice: + lhs = self + if lhs.is_memview_broadcast or rhs.is_memview_broadcast: + lhs.is_memview_broadcast = True + rhs.is_memview_broadcast = True + + def analyse_as_memview_scalar_assignment(self, rhs): + lhs = self.analyse_assignment(rhs) + if lhs: + rhs.is_memview_copy_assignment = lhs.is_memview_copy_assignment + return lhs + return self + + +class MemoryViewSliceNode(MemoryViewIndexNode): + + is_memview_slice = True + + # No-op slicing operation, this node will be replaced + is_ellipsis_noop = False + is_memview_scalar_assignment = False + is_memview_index = False + is_memview_broadcast = False + + def analyse_ellipsis_noop(self, env, getting): + """Slicing operations needing no evaluation, i.e. m[...] or m[:, :]""" + ### FIXME: replace directly + self.is_ellipsis_noop = all( + index.is_slice and index.start.is_none and index.stop.is_none and index.step.is_none + for index in self.indices) + + if self.is_ellipsis_noop: + self.type = self.base.type + + def analyse_operation(self, env, getting, axes): + from . import MemoryView + + if not getting: + self.is_memview_broadcast = True + self.none_error_message = "Cannot assign to None memoryview slice" + else: + self.none_error_message = "Cannot slice None memoryview slice" + + self.analyse_ellipsis_noop(env, getting) + if self.is_ellipsis_noop: + return + + self.index = None + self.is_temp = True + self.use_managed_ref = True + + if not MemoryView.validate_axes(self.pos, axes): + self.type = error_type + return + + self.type = PyrexTypes.MemoryViewSliceType(self.base.type.dtype, axes) + + if not (self.base.is_simple() or self.base.result_in_temp()): + self.base = self.base.coerce_to_temp(env) + + def analyse_assignment(self, rhs): + if not rhs.type.is_memoryviewslice and ( + self.type.dtype.assignable_from(rhs.type) or + rhs.type.is_pyobject): + # scalar assignment + return MemoryCopyScalar(self.pos, self) + else: + return MemoryCopySlice(self.pos, self) + def merged_indices(self, indices): """Return a new list of indices/slices with 'indices' merged into the current ones according to slicing rules. @@ -4585,29 +4585,29 @@ class MemoryViewSliceNode(MemoryViewIndexNode): new_indices += indices return new_indices - def is_simple(self): - if self.is_ellipsis_noop: - # TODO: fix SimpleCallNode.is_simple() - return self.base.is_simple() or self.base.result_in_temp() - - return self.result_in_temp() - - def calculate_result_code(self): - """This is called in case this is a no-op slicing node""" - return self.base.result() - - def generate_result_code(self, code): - if self.is_ellipsis_noop: - return ### FIXME: remove + def is_simple(self): + if self.is_ellipsis_noop: + # TODO: fix SimpleCallNode.is_simple() + return self.base.is_simple() or self.base.result_in_temp() + + return self.result_in_temp() + + def calculate_result_code(self): + """This is called in case this is a no-op slicing node""" + return self.base.result() + + def generate_result_code(self, code): + if self.is_ellipsis_noop: + return ### FIXME: remove buffer_entry = self.buffer_entry() have_gil = not self.in_nogil_context - # TODO Mark: this is insane, do it better + # TODO Mark: this is insane, do it better have_slices = False it = iter(self.indices) for index in self.original_indices: - if index.is_slice: - have_slices = True + if index.is_slice: + have_slices = True if not index.start.is_none: index.start = next(it) if not index.stop.is_none: @@ -4619,126 +4619,126 @@ class MemoryViewSliceNode(MemoryViewIndexNode): assert not list(it) - buffer_entry.generate_buffer_slice_code( - code, self.original_indices, self.result(), - have_gil=have_gil, have_slices=have_slices, - directives=code.globalstate.directives) - - def generate_assignment_code(self, rhs, code, overloaded_assignment=False): - if self.is_ellipsis_noop: - self.generate_subexpr_evaluation_code(code) - else: - self.generate_evaluation_code(code) - - if self.is_memview_scalar_assignment: - self.generate_memoryviewslice_assign_scalar_code(rhs, code) - else: - self.generate_memoryviewslice_setslice_code(rhs, code) - - if self.is_ellipsis_noop: - self.generate_subexpr_disposal_code(code) - else: - self.generate_disposal_code(code) - - rhs.generate_disposal_code(code) - rhs.free_temps(code) - - -class MemoryCopyNode(ExprNode): - """ - Wraps a memoryview slice for slice assignment. - - dst: destination mememoryview slice - """ - - subexprs = ['dst'] - - def __init__(self, pos, dst): - super(MemoryCopyNode, self).__init__(pos) - self.dst = dst - self.type = dst.type - - def generate_assignment_code(self, rhs, code, overloaded_assignment=False): - self.dst.generate_evaluation_code(code) - self._generate_assignment_code(rhs, code) - self.dst.generate_disposal_code(code) + buffer_entry.generate_buffer_slice_code( + code, self.original_indices, self.result(), + have_gil=have_gil, have_slices=have_slices, + directives=code.globalstate.directives) + + def generate_assignment_code(self, rhs, code, overloaded_assignment=False): + if self.is_ellipsis_noop: + self.generate_subexpr_evaluation_code(code) + else: + self.generate_evaluation_code(code) + + if self.is_memview_scalar_assignment: + self.generate_memoryviewslice_assign_scalar_code(rhs, code) + else: + self.generate_memoryviewslice_setslice_code(rhs, code) + + if self.is_ellipsis_noop: + self.generate_subexpr_disposal_code(code) + else: + self.generate_disposal_code(code) + + rhs.generate_disposal_code(code) + rhs.free_temps(code) + + +class MemoryCopyNode(ExprNode): + """ + Wraps a memoryview slice for slice assignment. + + dst: destination mememoryview slice + """ + + subexprs = ['dst'] + + def __init__(self, pos, dst): + super(MemoryCopyNode, self).__init__(pos) + self.dst = dst + self.type = dst.type + + def generate_assignment_code(self, rhs, code, overloaded_assignment=False): + self.dst.generate_evaluation_code(code) + self._generate_assignment_code(rhs, code) + self.dst.generate_disposal_code(code) self.dst.free_temps(code) - rhs.generate_disposal_code(code) - rhs.free_temps(code) - - -class MemoryCopySlice(MemoryCopyNode): - """ - Copy the contents of slice src to slice dst. Does not support indirect - slices. - - memslice1[...] = memslice2 - memslice1[:] = memslice2 - """ - - is_memview_copy_assignment = True - copy_slice_cname = "__pyx_memoryview_copy_contents" - - def _generate_assignment_code(self, src, code): - dst = self.dst - - src.type.assert_direct_dims(src.pos) - dst.type.assert_direct_dims(dst.pos) - - code.putln(code.error_goto_if_neg( - "%s(%s, %s, %d, %d, %d)" % (self.copy_slice_cname, - src.result(), dst.result(), - src.type.ndim, dst.type.ndim, - dst.type.dtype.is_pyobject), - dst.pos)) - - -class MemoryCopyScalar(MemoryCopyNode): - """ - Assign a scalar to a slice. dst must be simple, scalar will be assigned - to a correct type and not just something assignable. - - memslice1[...] = 0.0 - memslice1[:] = 0.0 - """ - - def __init__(self, pos, dst): - super(MemoryCopyScalar, self).__init__(pos, dst) - self.type = dst.type.dtype - - def _generate_assignment_code(self, scalar, code): + rhs.generate_disposal_code(code) + rhs.free_temps(code) + + +class MemoryCopySlice(MemoryCopyNode): + """ + Copy the contents of slice src to slice dst. Does not support indirect + slices. + + memslice1[...] = memslice2 + memslice1[:] = memslice2 + """ + + is_memview_copy_assignment = True + copy_slice_cname = "__pyx_memoryview_copy_contents" + + def _generate_assignment_code(self, src, code): + dst = self.dst + + src.type.assert_direct_dims(src.pos) + dst.type.assert_direct_dims(dst.pos) + + code.putln(code.error_goto_if_neg( + "%s(%s, %s, %d, %d, %d)" % (self.copy_slice_cname, + src.result(), dst.result(), + src.type.ndim, dst.type.ndim, + dst.type.dtype.is_pyobject), + dst.pos)) + + +class MemoryCopyScalar(MemoryCopyNode): + """ + Assign a scalar to a slice. dst must be simple, scalar will be assigned + to a correct type and not just something assignable. + + memslice1[...] = 0.0 + memslice1[:] = 0.0 + """ + + def __init__(self, pos, dst): + super(MemoryCopyScalar, self).__init__(pos, dst) + self.type = dst.type.dtype + + def _generate_assignment_code(self, scalar, code): from . import MemoryView - self.dst.type.assert_direct_dims(self.dst.pos) - - dtype = self.dst.type.dtype - type_decl = dtype.declaration_code("") - slice_decl = self.dst.type.declaration_code("") - - code.begin_block() - code.putln("%s __pyx_temp_scalar = %s;" % (type_decl, scalar.result())) - if self.dst.result_in_temp() or self.dst.is_simple(): - dst_temp = self.dst.result() - else: - code.putln("%s __pyx_temp_slice = %s;" % (slice_decl, self.dst.result())) - dst_temp = "__pyx_temp_slice" - - slice_iter_obj = MemoryView.slice_iter(self.dst.type, dst_temp, - self.dst.type.ndim, code) - p = slice_iter_obj.start_loops() - - if dtype.is_pyobject: - code.putln("Py_DECREF(*(PyObject **) %s);" % p) - - code.putln("*((%s *) %s) = __pyx_temp_scalar;" % (type_decl, p)) - - if dtype.is_pyobject: - code.putln("Py_INCREF(__pyx_temp_scalar);") - - slice_iter_obj.end_loops() - code.end_block() - - + self.dst.type.assert_direct_dims(self.dst.pos) + + dtype = self.dst.type.dtype + type_decl = dtype.declaration_code("") + slice_decl = self.dst.type.declaration_code("") + + code.begin_block() + code.putln("%s __pyx_temp_scalar = %s;" % (type_decl, scalar.result())) + if self.dst.result_in_temp() or self.dst.is_simple(): + dst_temp = self.dst.result() + else: + code.putln("%s __pyx_temp_slice = %s;" % (slice_decl, self.dst.result())) + dst_temp = "__pyx_temp_slice" + + slice_iter_obj = MemoryView.slice_iter(self.dst.type, dst_temp, + self.dst.type.ndim, code) + p = slice_iter_obj.start_loops() + + if dtype.is_pyobject: + code.putln("Py_DECREF(*(PyObject **) %s);" % p) + + code.putln("*((%s *) %s) = __pyx_temp_scalar;" % (type_decl, p)) + + if dtype.is_pyobject: + code.putln("Py_INCREF(__pyx_temp_scalar);") + + slice_iter_obj.end_loops() + code.end_block() + + class SliceIndexNode(ExprNode): # 2-element slice indexing # @@ -4764,15 +4764,15 @@ class SliceIndexNode(ExprNode): return PyrexTypes.c_array_type(base_type.base_type, None) return py_object_type - def inferable_item_node(self, index=0): - # slicing shouldn't change the result type of the base, but the index might - if index is not not_a_constant and self.start: - if self.start.has_constant_result(): - index += self.start.constant_result - else: - index = not_a_constant - return self.base.inferable_item_node(index) - + def inferable_item_node(self, index=0): + # slicing shouldn't change the result type of the base, but the index might + if index is not not_a_constant and self.start: + if self.start.has_constant_result(): + index += self.start.constant_result + else: + index = not_a_constant + return self.base.inferable_item_node(index) + def may_be_none(self): base_type = self.base.type if base_type: @@ -4806,7 +4806,7 @@ class SliceIndexNode(ExprNode): stop = self.stop.compile_time_value(denv) try: return base[start:stop] - except Exception as e: + except Exception as e: self.compile_time_value_error(e) def analyse_target_declaration(self, env): @@ -4842,13 +4842,13 @@ class SliceIndexNode(ExprNode): check_negative_indices(self.start, self.stop) base_type = self.base.type - if base_type.is_array and not getting: - # cannot assign directly to C array => try to assign by making a copy - if not self.start and not self.stop: - self.type = base_type - else: - self.type = PyrexTypes.CPtrType(base_type.base_type) - elif base_type.is_string or base_type.is_cpp_string: + if base_type.is_array and not getting: + # cannot assign directly to C array => try to assign by making a copy + if not self.start and not self.stop: + self.type = base_type + else: + self.type = PyrexTypes.CPtrType(base_type.base_type) + elif base_type.is_string or base_type.is_cpp_string: self.type = default_str_type(env) elif base_type.is_pyunicode_ptr: self.type = unicode_type @@ -4880,59 +4880,59 @@ class SliceIndexNode(ExprNode): ).analyse_types(env) else: c_int = PyrexTypes.c_py_ssize_t_type - - def allow_none(node, default_value, env): - # Coerce to Py_ssize_t, but allow None as meaning the default slice bound. - from .UtilNodes import EvalWithTempExprNode, ResultRefNode - - node_ref = ResultRefNode(node) - new_expr = CondExprNode( - node.pos, - true_val=IntNode( - node.pos, - type=c_int, - value=default_value, - constant_result=int(default_value) if default_value.isdigit() else not_a_constant, - ), - false_val=node_ref.coerce_to(c_int, env), - test=PrimaryCmpNode( - node.pos, - operand1=node_ref, - operator='is', - operand2=NoneNode(node.pos), - ).analyse_types(env) - ).analyse_result_type(env) - return EvalWithTempExprNode(node_ref, new_expr) - + + def allow_none(node, default_value, env): + # Coerce to Py_ssize_t, but allow None as meaning the default slice bound. + from .UtilNodes import EvalWithTempExprNode, ResultRefNode + + node_ref = ResultRefNode(node) + new_expr = CondExprNode( + node.pos, + true_val=IntNode( + node.pos, + type=c_int, + value=default_value, + constant_result=int(default_value) if default_value.isdigit() else not_a_constant, + ), + false_val=node_ref.coerce_to(c_int, env), + test=PrimaryCmpNode( + node.pos, + operand1=node_ref, + operator='is', + operand2=NoneNode(node.pos), + ).analyse_types(env) + ).analyse_result_type(env) + return EvalWithTempExprNode(node_ref, new_expr) + if self.start: - if self.start.type.is_pyobject: - self.start = allow_none(self.start, '0', env) + if self.start.type.is_pyobject: + self.start = allow_none(self.start, '0', env) self.start = self.start.coerce_to(c_int, env) if self.stop: - if self.stop.type.is_pyobject: - self.stop = allow_none(self.stop, 'PY_SSIZE_T_MAX', env) + if self.stop.type.is_pyobject: + self.stop = allow_none(self.stop, 'PY_SSIZE_T_MAX', env) self.stop = self.stop.coerce_to(c_int, env) self.is_temp = 1 return self - def analyse_as_type(self, env): - base_type = self.base.analyse_as_type(env) - if base_type and not base_type.is_pyobject: - if not self.start and not self.stop: - # memory view - from . import MemoryView - env.use_utility_code(MemoryView.view_utility_code) - none_node = NoneNode(self.pos) - slice_node = SliceNode( - self.pos, - start=none_node, - stop=none_node, - step=none_node, - ) - return PyrexTypes.MemoryViewSliceType( - base_type, MemoryView.get_axes_specs(env, [slice_node])) - return None - + def analyse_as_type(self, env): + base_type = self.base.analyse_as_type(env) + if base_type and not base_type.is_pyobject: + if not self.start and not self.stop: + # memory view + from . import MemoryView + env.use_utility_code(MemoryView.view_utility_code) + none_node = NoneNode(self.pos) + slice_node = SliceNode( + self.pos, + start=none_node, + stop=none_node, + step=none_node, + ) + return PyrexTypes.MemoryViewSliceType( + base_type, MemoryView.get_axes_specs(env, [slice_node])) + return None + nogil_check = Node.gil_error gil_message = "Slicing Python object" @@ -4951,11 +4951,11 @@ class SliceIndexNode(ExprNode): "default encoding required for conversion from '%s' to '%s'" % (self.base.type, dst_type)) self.type = dst_type - if dst_type.is_array and self.base.type.is_array: - if not self.start and not self.stop: - # redundant slice building, copy C arrays directly - return self.base.coerce_to(dst_type, env) - # else: check array size if possible + if dst_type.is_array and self.base.type.is_array: + if not self.start and not self.stop: + # redundant slice building, copy C arrays directly + return self.base.coerce_to(dst_type, env) + # else: check array size if possible return super(SliceIndexNode, self).coerce_to(dst_type, env) def generate_result_code(self, code): @@ -4970,7 +4970,7 @@ class SliceIndexNode(ExprNode): stop_code = self.stop_code() if self.base.type.is_string: base_result = self.base.result() - if self.base.type not in (PyrexTypes.c_char_ptr_type, PyrexTypes.c_const_char_ptr_type): + if self.base.type not in (PyrexTypes.c_char_ptr_type, PyrexTypes.c_const_char_ptr_type): base_result = '((const char*)%s)' % base_result if self.type is bytearray_type: type_name = 'ByteArray' @@ -5059,8 +5059,8 @@ class SliceIndexNode(ExprNode): code.error_goto_if_null(result, self.pos))) code.put_gotref(self.py_result()) - def generate_assignment_code(self, rhs, code, overloaded_assignment=False, - exception_check=None, exception_value=None): + def generate_assignment_code(self, rhs, code, overloaded_assignment=False, + exception_check=None, exception_value=None): self.generate_subexpr_evaluation_code(code) if self.type.is_pyobject: code.globalstate.use_utility_code(self.set_slice_utility_code) @@ -5075,20 +5075,20 @@ class SliceIndexNode(ExprNode): has_c_start, has_c_stop, bool(code.globalstate.directives['wraparound']))) else: - start_offset = self.start_code() if self.start else '0' + start_offset = self.start_code() if self.start else '0' if rhs.type.is_array: array_length = rhs.type.size self.generate_slice_guard_code(code, array_length) else: - array_length = '%s - %s' % (self.stop_code(), start_offset) - - code.globalstate.use_utility_code(UtilityCode.load_cached("IncludeStringH", "StringTools.c")) - code.putln("memcpy(&(%s[%s]), %s, sizeof(%s[0]) * (%s));" % ( - self.base.result(), start_offset, - rhs.result(), - self.base.result(), array_length - )) - + array_length = '%s - %s' % (self.stop_code(), start_offset) + + code.globalstate.use_utility_code(UtilityCode.load_cached("IncludeStringH", "StringTools.c")) + code.putln("memcpy(&(%s[%s]), %s, sizeof(%s[0]) * (%s));" % ( + self.base.result(), start_offset, + rhs.result(), + self.base.result(), array_length + )) + self.generate_subexpr_disposal_code(code) self.free_subexpr_temps(code) rhs.generate_disposal_code(code) @@ -5136,77 +5136,77 @@ class SliceIndexNode(ExprNode): if not self.base.type.is_array: return slice_size = self.base.type.size - try: - total_length = slice_size = int(slice_size) - except ValueError: - total_length = None - + try: + total_length = slice_size = int(slice_size) + except ValueError: + total_length = None + start = stop = None if self.stop: stop = self.stop.result() try: stop = int(stop) if stop < 0: - if total_length is None: - slice_size = '%s + %d' % (slice_size, stop) - else: - slice_size += stop + if total_length is None: + slice_size = '%s + %d' % (slice_size, stop) + else: + slice_size += stop else: slice_size = stop stop = None except ValueError: pass - + if self.start: start = self.start.result() try: start = int(start) if start < 0: - if total_length is None: - start = '%s + %d' % (self.base.type.size, start) - else: - start += total_length - if isinstance(slice_size, _py_int_types): - slice_size -= start - else: - slice_size = '%s - (%s)' % (slice_size, start) + if total_length is None: + start = '%s + %d' % (self.base.type.size, start) + else: + start += total_length + if isinstance(slice_size, _py_int_types): + slice_size -= start + else: + slice_size = '%s - (%s)' % (slice_size, start) start = None except ValueError: pass - - runtime_check = None - compile_time_check = False - try: - int_target_size = int(target_size) - except ValueError: - int_target_size = None - else: - compile_time_check = isinstance(slice_size, _py_int_types) - - if compile_time_check and slice_size < 0: - if int_target_size > 0: + + runtime_check = None + compile_time_check = False + try: + int_target_size = int(target_size) + except ValueError: + int_target_size = None + else: + compile_time_check = isinstance(slice_size, _py_int_types) + + if compile_time_check and slice_size < 0: + if int_target_size > 0: error(self.pos, "Assignment to empty slice.") - elif compile_time_check and start is None and stop is None: + elif compile_time_check and start is None and stop is None: # we know the exact slice length - if int_target_size != slice_size: - error(self.pos, "Assignment to slice of wrong length, expected %s, got %s" % ( - slice_size, target_size)) + if int_target_size != slice_size: + error(self.pos, "Assignment to slice of wrong length, expected %s, got %s" % ( + slice_size, target_size)) elif start is not None: if stop is None: stop = slice_size - runtime_check = "(%s)-(%s)" % (stop, start) - elif stop is not None: - runtime_check = stop - else: - runtime_check = slice_size - - if runtime_check: - code.putln("if (unlikely((%s) != (%s))) {" % (runtime_check, target_size)) - code.putln( - 'PyErr_Format(PyExc_ValueError, "Assignment to slice of wrong length,' - ' expected %%" CYTHON_FORMAT_SSIZE_T "d, got %%" CYTHON_FORMAT_SSIZE_T "d",' - ' (Py_ssize_t)(%s), (Py_ssize_t)(%s));' % ( - target_size, runtime_check)) + runtime_check = "(%s)-(%s)" % (stop, start) + elif stop is not None: + runtime_check = stop + else: + runtime_check = slice_size + + if runtime_check: + code.putln("if (unlikely((%s) != (%s))) {" % (runtime_check, target_size)) + code.putln( + 'PyErr_Format(PyExc_ValueError, "Assignment to slice of wrong length,' + ' expected %%" CYTHON_FORMAT_SSIZE_T "d, got %%" CYTHON_FORMAT_SSIZE_T "d",' + ' (Py_ssize_t)(%s), (Py_ssize_t)(%s));' % ( + target_size, runtime_check)) code.putln(code.error_goto(self.pos)) code.putln("}") @@ -5237,7 +5237,7 @@ class SliceNode(ExprNode): # step ExprNode subexprs = ['start', 'stop', 'step'] - is_slice = True + is_slice = True type = slice_type is_temp = 1 @@ -5253,7 +5253,7 @@ class SliceNode(ExprNode): step = self.step.compile_time_value(denv) try: return slice(start, stop, step) - except Exception as e: + except Exception as e: self.compile_time_value_error(e) def may_be_none(self): @@ -5278,11 +5278,11 @@ class SliceNode(ExprNode): def generate_result_code(self, code): if self.is_literal: - dedup_key = make_dedup_key(self.type, (self,)) - self.result_code = code.get_py_const(py_object_type, 'slice', cleanup_level=2, dedup_key=dedup_key) - code = code.get_cached_constants_writer(self.result_code) - if code is None: - return # already initialised + dedup_key = make_dedup_key(self.type, (self,)) + self.result_code = code.get_py_const(py_object_type, 'slice', cleanup_level=2, dedup_key=dedup_key) + code = code.get_cached_constants_writer(self.result_code) + if code is None: + return # already initialised code.mark_pos(self.pos) code.putln( @@ -5357,7 +5357,7 @@ class CallNode(ExprNode): may_return_none = None def infer_type(self, env): - # TODO(robertwb): Reduce redundancy with analyse_types. + # TODO(robertwb): Reduce redundancy with analyse_types. function = self.function func_type = function.infer_type(env) if isinstance(function, NewExprNode): @@ -5371,15 +5371,15 @@ class CallNode(ExprNode): if func_type.is_ptr: func_type = func_type.base_type if func_type.is_cfunction: - if getattr(self.function, 'entry', None) and hasattr(self, 'args'): - alternatives = self.function.entry.all_alternatives() - arg_types = [arg.infer_type(env) for arg in self.args] - func_entry = PyrexTypes.best_match(arg_types, alternatives) - if func_entry: - func_type = func_entry.type - if func_type.is_ptr: - func_type = func_type.base_type - return func_type.return_type + if getattr(self.function, 'entry', None) and hasattr(self, 'args'): + alternatives = self.function.entry.all_alternatives() + arg_types = [arg.infer_type(env) for arg in self.args] + func_entry = PyrexTypes.best_match(arg_types, alternatives) + if func_entry: + func_type = func_entry.type + if func_type.is_ptr: + func_type = func_type.base_type + return func_type.return_type return func_type.return_type elif func_type is type_type: if function.is_name and function.entry and function.entry.type: @@ -5467,7 +5467,7 @@ class CallNode(ExprNode): return self self.function = RawCNameExprNode(self.function.pos, constructor.type) self.function.entry = constructor - self.function.set_cname(type.empty_declaration_code()) + self.function.set_cname(type.empty_declaration_code()) self.analyse_c_function_call(env) self.type = type return True @@ -5513,7 +5513,7 @@ class SimpleCallNode(CallNode): args = [arg.compile_time_value(denv) for arg in self.args] try: return function(*args) - except Exception as e: + except Exception as e: self.compile_time_value_error(e) def analyse_as_type(self, env): @@ -5554,8 +5554,8 @@ class SimpleCallNode(CallNode): func_type = self.function_type() self.is_numpy_call_with_exprs = False - if (has_np_pythran(env) and function.is_numpy_attribute and - pythran_is_numpy_func_supported(function)): + if (has_np_pythran(env) and function.is_numpy_attribute and + pythran_is_numpy_func_supported(function)): has_pythran_args = True self.arg_tuple = TupleNode(self.pos, args = self.args) self.arg_tuple = self.arg_tuple.analyse_types(env) @@ -5563,24 +5563,24 @@ class SimpleCallNode(CallNode): has_pythran_args &= is_pythran_supported_node_or_none(arg) self.is_numpy_call_with_exprs = bool(has_pythran_args) if self.is_numpy_call_with_exprs: - env.add_include_file(pythran_get_func_include_file(function)) + env.add_include_file(pythran_get_func_include_file(function)) return NumPyMethodCallNode.from_node( self, function_cname=pythran_functor(function), arg_tuple=self.arg_tuple, - type=PythranExpr(pythran_func_type(function, self.arg_tuple.args)), + type=PythranExpr(pythran_func_type(function, self.arg_tuple.args)), ) elif func_type.is_pyobject: self.arg_tuple = TupleNode(self.pos, args = self.args) - self.arg_tuple = self.arg_tuple.analyse_types(env).coerce_to_pyobject(env) + self.arg_tuple = self.arg_tuple.analyse_types(env).coerce_to_pyobject(env) self.args = None self.set_py_result_type(function, func_type) self.is_temp = 1 else: self.args = [ arg.analyse_types(env) for arg in self.args ] self.analyse_c_function_call(env) - if func_type.exception_check == '+': - self.is_temp = True + if func_type.exception_check == '+': + self.is_temp = True return self def function_type(self): @@ -5620,7 +5620,7 @@ class SimpleCallNode(CallNode): return elif hasattr(self.function, 'entry'): overloaded_entry = self.function.entry - elif self.function.is_subscript and self.function.is_fused_index: + elif self.function.is_subscript and self.function.is_fused_index: overloaded_entry = self.function.type.entry else: overloaded_entry = None @@ -5632,8 +5632,8 @@ class SimpleCallNode(CallNode): else: alternatives = overloaded_entry.all_alternatives() - entry = PyrexTypes.best_match( - [arg.type for arg in args], alternatives, self.pos, env, args) + entry = PyrexTypes.best_match( + [arg.type for arg in args], alternatives, self.pos, env, args) if not entry: self.type = PyrexTypes.error_type @@ -5641,8 +5641,8 @@ class SimpleCallNode(CallNode): return entry.used = True - if not func_type.is_cpp_class: - self.function.entry = entry + if not func_type.is_cpp_class: + self.function.entry = entry self.function.type = entry.type func_type = self.function_type() else: @@ -5692,7 +5692,7 @@ class SimpleCallNode(CallNode): # Coerce arguments some_args_in_temps = False - for i in range(min(max_nargs, actual_nargs)): + for i in range(min(max_nargs, actual_nargs)): formal_arg = func_type.args[i] formal_type = formal_arg.type arg = args[i].coerce_to(formal_type, env) @@ -5722,13 +5722,13 @@ class SimpleCallNode(CallNode): args[i] = arg # handle additional varargs parameters - for i in range(max_nargs, actual_nargs): + for i in range(max_nargs, actual_nargs): arg = args[i] if arg.type.is_pyobject: - if arg.type is str_type: - arg_ctype = PyrexTypes.c_char_ptr_type - else: - arg_ctype = arg.type.default_coerced_ctype() + if arg.type is str_type: + arg_ctype = PyrexTypes.c_char_ptr_type + else: + arg_ctype = arg.type.default_coerced_ctype() if arg_ctype is None: error(self.args[i].pos, "Python object cannot be passed as a varargs parameter") @@ -5743,7 +5743,7 @@ class SimpleCallNode(CallNode): # sure they are either all temps or all not temps (except # for the last argument, which is evaluated last in any # case) - for i in range(actual_nargs-1): + for i in range(actual_nargs-1): if i == 0 and self.self is not None: continue # self is ok arg = args[i] @@ -5774,22 +5774,22 @@ class SimpleCallNode(CallNode): self.type = func_type.return_type if self.function.is_name or self.function.is_attribute: - func_entry = self.function.entry - if func_entry and (func_entry.utility_code or func_entry.utility_code_definition): - self.is_temp = 1 # currently doesn't work for self.calculate_result_code() + func_entry = self.function.entry + if func_entry and (func_entry.utility_code or func_entry.utility_code_definition): + self.is_temp = 1 # currently doesn't work for self.calculate_result_code() if self.type.is_pyobject: self.result_ctype = py_object_type self.is_temp = 1 - elif func_type.exception_value is not None or func_type.exception_check: + elif func_type.exception_value is not None or func_type.exception_check: self.is_temp = 1 elif self.type.is_memoryviewslice: self.is_temp = 1 # func_type.exception_check = True - if self.is_temp and self.type.is_reference: - self.type = PyrexTypes.CFakeReferenceType(self.type.ref_base_type) - + if self.is_temp and self.type.is_reference: + self.type = PyrexTypes.CFakeReferenceType(self.type.ref_base_type) + # Called in 'nogil' context? self.nogil = env.nogil if (self.nogil and @@ -5836,12 +5836,12 @@ class SimpleCallNode(CallNode): result = "%s(%s)" % (self.function.result(), ', '.join(arg_list_code)) return result - def is_c_result_required(self): - func_type = self.function_type() - if not func_type.exception_value or func_type.exception_check == '+': - return False # skip allocation of unused result temp - return True - + def is_c_result_required(self): + func_type = self.function_type() + if not func_type.exception_value or func_type.exception_check == '+': + return False # skip allocation of unused result temp + return True + def generate_evaluation_code(self, code): function = self.function if function.is_name or function.is_attribute: @@ -5934,7 +5934,7 @@ class SimpleCallNode(CallNode): elif self.type.is_memoryviewslice: assert self.is_temp exc_checks.append(self.type.error_condition(self.result())) - elif func_type.exception_check != '+': + elif func_type.exception_check != '+': exc_val = func_type.exception_value exc_check = func_type.exception_check if exc_val is not None: @@ -5956,9 +5956,9 @@ class SimpleCallNode(CallNode): else: lhs = "" if func_type.exception_check == '+': - translate_cpp_exception(code, self.pos, '%s%s;' % (lhs, rhs), - self.result() if self.type.is_pyobject else None, - func_type.exception_value, self.nogil) + translate_cpp_exception(code, self.pos, '%s%s;' % (lhs, rhs), + self.result() if self.type.is_pyobject else None, + func_type.exception_value, self.nogil) else: if exc_checks: goto_error = code.error_goto_if(" && ".join(exc_checks), self.pos) @@ -5992,7 +5992,7 @@ class NumPyMethodCallNode(ExprNode): code.putln("// function evaluation code for numpy function") code.putln("__Pyx_call_destructor(%s);" % self.result()) - code.putln("new (&%s) decltype(%s){%s{}(%s)};" % ( + code.putln("new (&%s) decltype(%s){%s{}(%s)};" % ( self.result(), self.result(), self.function_cname, @@ -6034,7 +6034,7 @@ class PyMethodCallNode(SimpleCallNode): code.putln("%s = NULL;" % self_arg) arg_offset_cname = None if len(args) > 1: - arg_offset_cname = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False) + arg_offset_cname = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False) code.putln("%s = 0;" % arg_offset_cname) def attribute_is_likely_method(attr): @@ -6058,7 +6058,7 @@ class PyMethodCallNode(SimpleCallNode): else: likely_method = 'unlikely' - code.putln("if (CYTHON_UNPACK_METHODS && %s(PyMethod_Check(%s))) {" % (likely_method, function)) + code.putln("if (CYTHON_UNPACK_METHODS && %s(PyMethod_Check(%s))) {" % (likely_method, function)) code.putln("%s = PyMethod_GET_SELF(%s);" % (self_arg, function)) # the following is always true in Py3 (kept only for safety), # but is false for unbound methods in Py2 @@ -6076,85 +6076,85 @@ class PyMethodCallNode(SimpleCallNode): if not args: # fastest special case: try to avoid tuple creation code.globalstate.use_utility_code( - UtilityCode.load_cached("PyObjectCallNoArg", "ObjectHandling.c")) - code.globalstate.use_utility_code( + UtilityCode.load_cached("PyObjectCallNoArg", "ObjectHandling.c")) + code.globalstate.use_utility_code( UtilityCode.load_cached("PyObjectCallOneArg", "ObjectHandling.c")) code.putln( - "%s = (%s) ? __Pyx_PyObject_CallOneArg(%s, %s) : __Pyx_PyObject_CallNoArg(%s);" % ( - self.result(), self_arg, + "%s = (%s) ? __Pyx_PyObject_CallOneArg(%s, %s) : __Pyx_PyObject_CallNoArg(%s);" % ( + self.result(), self_arg, function, self_arg, - function)) - code.put_xdecref_clear(self_arg, py_object_type) + function)) + code.put_xdecref_clear(self_arg, py_object_type) code.funcstate.release_temp(self_arg) - code.putln(code.error_goto_if_null(self.result(), self.pos)) - code.put_gotref(self.py_result()) - elif len(args) == 1: - # fastest special case: try to avoid tuple creation + code.putln(code.error_goto_if_null(self.result(), self.pos)) + code.put_gotref(self.py_result()) + elif len(args) == 1: + # fastest special case: try to avoid tuple creation + code.globalstate.use_utility_code( + UtilityCode.load_cached("PyObjectCall2Args", "ObjectHandling.c")) code.globalstate.use_utility_code( - UtilityCode.load_cached("PyObjectCall2Args", "ObjectHandling.c")) - code.globalstate.use_utility_code( - UtilityCode.load_cached("PyObjectCallOneArg", "ObjectHandling.c")) - arg = args[0] + UtilityCode.load_cached("PyObjectCallOneArg", "ObjectHandling.c")) + arg = args[0] code.putln( - "%s = (%s) ? __Pyx_PyObject_Call2Args(%s, %s, %s) : __Pyx_PyObject_CallOneArg(%s, %s);" % ( - self.result(), self_arg, - function, self_arg, arg.py_result(), - function, arg.py_result())) - code.put_xdecref_clear(self_arg, py_object_type) - code.funcstate.release_temp(self_arg) - arg.generate_disposal_code(code) - arg.free_temps(code) - code.putln(code.error_goto_if_null(self.result(), self.pos)) + "%s = (%s) ? __Pyx_PyObject_Call2Args(%s, %s, %s) : __Pyx_PyObject_CallOneArg(%s, %s);" % ( + self.result(), self_arg, + function, self_arg, arg.py_result(), + function, arg.py_result())) + code.put_xdecref_clear(self_arg, py_object_type) + code.funcstate.release_temp(self_arg) + arg.generate_disposal_code(code) + arg.free_temps(code) + code.putln(code.error_goto_if_null(self.result(), self.pos)) code.put_gotref(self.py_result()) else: - code.globalstate.use_utility_code( - UtilityCode.load_cached("PyFunctionFastCall", "ObjectHandling.c")) - code.globalstate.use_utility_code( - UtilityCode.load_cached("PyCFunctionFastCall", "ObjectHandling.c")) - for test_func, call_prefix in [('PyFunction_Check', 'Py'), ('__Pyx_PyFastCFunction_Check', 'PyC')]: - code.putln("#if CYTHON_FAST_%sCALL" % call_prefix.upper()) - code.putln("if (%s(%s)) {" % (test_func, function)) - code.putln("PyObject *%s[%d] = {%s, %s};" % ( - Naming.quick_temp_cname, - len(args)+1, - self_arg, - ', '.join(arg.py_result() for arg in args))) - code.putln("%s = __Pyx_%sFunction_FastCall(%s, %s+1-%s, %d+%s); %s" % ( - self.result(), - call_prefix, - function, - Naming.quick_temp_cname, - arg_offset_cname, - len(args), - arg_offset_cname, - code.error_goto_if_null(self.result(), self.pos))) - code.put_xdecref_clear(self_arg, py_object_type) - code.put_gotref(self.py_result()) - for arg in args: - arg.generate_disposal_code(code) - code.putln("} else") - code.putln("#endif") - - code.putln("{") + code.globalstate.use_utility_code( + UtilityCode.load_cached("PyFunctionFastCall", "ObjectHandling.c")) + code.globalstate.use_utility_code( + UtilityCode.load_cached("PyCFunctionFastCall", "ObjectHandling.c")) + for test_func, call_prefix in [('PyFunction_Check', 'Py'), ('__Pyx_PyFastCFunction_Check', 'PyC')]: + code.putln("#if CYTHON_FAST_%sCALL" % call_prefix.upper()) + code.putln("if (%s(%s)) {" % (test_func, function)) + code.putln("PyObject *%s[%d] = {%s, %s};" % ( + Naming.quick_temp_cname, + len(args)+1, + self_arg, + ', '.join(arg.py_result() for arg in args))) + code.putln("%s = __Pyx_%sFunction_FastCall(%s, %s+1-%s, %d+%s); %s" % ( + self.result(), + call_prefix, + function, + Naming.quick_temp_cname, + arg_offset_cname, + len(args), + arg_offset_cname, + code.error_goto_if_null(self.result(), self.pos))) + code.put_xdecref_clear(self_arg, py_object_type) + code.put_gotref(self.py_result()) + for arg in args: + arg.generate_disposal_code(code) + code.putln("} else") + code.putln("#endif") + + code.putln("{") args_tuple = code.funcstate.allocate_temp(py_object_type, manage_ref=True) code.putln("%s = PyTuple_New(%d+%s); %s" % ( - args_tuple, len(args), arg_offset_cname, + args_tuple, len(args), arg_offset_cname, code.error_goto_if_null(args_tuple, self.pos))) code.put_gotref(args_tuple) if len(args) > 1: code.putln("if (%s) {" % self_arg) - code.putln("__Pyx_GIVEREF(%s); PyTuple_SET_ITEM(%s, 0, %s); %s = NULL;" % ( - self_arg, args_tuple, self_arg, self_arg)) # stealing owned ref in this case + code.putln("__Pyx_GIVEREF(%s); PyTuple_SET_ITEM(%s, 0, %s); %s = NULL;" % ( + self_arg, args_tuple, self_arg, self_arg)) # stealing owned ref in this case code.funcstate.release_temp(self_arg) if len(args) > 1: code.putln("}") for i, arg in enumerate(args): arg.make_owned_reference(code) - code.put_giveref(arg.py_result()) + code.put_giveref(arg.py_result()) code.putln("PyTuple_SET_ITEM(%s, %d+%s, %s);" % ( - args_tuple, i, arg_offset_cname, arg.py_result())) + args_tuple, i, arg_offset_cname, arg.py_result())) if len(args) > 1: code.funcstate.release_temp(arg_offset_cname) @@ -6176,7 +6176,7 @@ class PyMethodCallNode(SimpleCallNode): if len(args) == 1: code.putln("}") - code.putln("}") # !CYTHON_FAST_PYCALL + code.putln("}") # !CYTHON_FAST_PYCALL if reuse_function_temp: self.function.generate_disposal_code(code) @@ -6205,8 +6205,8 @@ class InlinedDefNodeCallNode(CallNode): return False if len(func_type.args) != len(self.args): return False - if func_type.num_kwonly_args: - return False # actually wrong number of arguments + if func_type.num_kwonly_args: + return False # actually wrong number of arguments return True def analyse_types(self, env): @@ -6218,7 +6218,7 @@ class InlinedDefNodeCallNode(CallNode): # Coerce arguments some_args_in_temps = False - for i in range(actual_nargs): + for i in range(actual_nargs): formal_type = func_type.args[i].type arg = self.args[i].coerce_to(formal_type, env) if arg.is_temp: @@ -6245,7 +6245,7 @@ class InlinedDefNodeCallNode(CallNode): # sure they are either all temps or all not temps (except # for the last argument, which is evaluated last in any # case) - for i in range(actual_nargs-1): + for i in range(actual_nargs-1): arg = self.args[i] if arg.nonlocally_immutable(): # locals, C functions, unassignable types are safe. @@ -6374,12 +6374,12 @@ class GeneralCallNode(CallNode): keyword_args = self.keyword_args.compile_time_value(denv) try: return function(*positional_args, **keyword_args) - except Exception as e: + except Exception as e: self.compile_time_value_error(e) def explicit_args_kwds(self): - if (self.keyword_args and not self.keyword_args.is_dict_literal or - not self.positional_args.is_sequence_constructor): + if (self.keyword_args and not self.keyword_args.is_dict_literal or + not self.positional_args.is_sequence_constructor): raise CompileError(self.pos, 'Compile-time keyword arguments must be explicit.') return self.positional_args.args, self.keyword_args @@ -6425,7 +6425,7 @@ class GeneralCallNode(CallNode): if not isinstance(self.positional_args, TupleNode): # has starred argument return self - if not self.keyword_args.is_dict_literal: + if not self.keyword_args.is_dict_literal: # keywords come from arbitrary expression => nothing to do here return self function = self.function @@ -6588,13 +6588,13 @@ class AsTupleNode(ExprNode): arg = self.arg.compile_time_value(denv) try: return tuple(arg) - except Exception as e: + except Exception as e: self.compile_time_value_error(e) def analyse_types(self, env): - self.arg = self.arg.analyse_types(env).coerce_to_pyobject(env) - if self.arg.type is tuple_type: - return self.arg.as_none_safe_node("'NoneType' object is not iterable") + self.arg = self.arg.analyse_types(env).coerce_to_pyobject(env) + if self.arg.type is tuple_type: + return self.arg.as_none_safe_node("'NoneType' object is not iterable") self.type = tuple_type return self @@ -6614,159 +6614,159 @@ class AsTupleNode(ExprNode): code.put_gotref(self.py_result()) -class MergedDictNode(ExprNode): - # Helper class for keyword arguments and other merged dicts. - # - # keyword_args [DictNode or other ExprNode] - - subexprs = ['keyword_args'] - is_temp = 1 - type = dict_type - reject_duplicates = True - - def calculate_constant_result(self): - result = {} - reject_duplicates = self.reject_duplicates - for item in self.keyword_args: - if item.is_dict_literal: - # process items in order - items = ((key.constant_result, value.constant_result) - for key, value in item.key_value_pairs) - else: - items = item.constant_result.iteritems() - - for key, value in items: - if reject_duplicates and key in result: - raise ValueError("duplicate keyword argument found: %s" % key) - result[key] = value - - self.constant_result = result - - def compile_time_value(self, denv): - result = {} - reject_duplicates = self.reject_duplicates - for item in self.keyword_args: - if item.is_dict_literal: - # process items in order - items = [(key.compile_time_value(denv), value.compile_time_value(denv)) - for key, value in item.key_value_pairs] - else: - items = item.compile_time_value(denv).iteritems() - - try: - for key, value in items: - if reject_duplicates and key in result: - raise ValueError("duplicate keyword argument found: %s" % key) - result[key] = value - except Exception as e: - self.compile_time_value_error(e) - return result - - def type_dependencies(self, env): - return () - - def infer_type(self, env): - return dict_type - - def analyse_types(self, env): +class MergedDictNode(ExprNode): + # Helper class for keyword arguments and other merged dicts. + # + # keyword_args [DictNode or other ExprNode] + + subexprs = ['keyword_args'] + is_temp = 1 + type = dict_type + reject_duplicates = True + + def calculate_constant_result(self): + result = {} + reject_duplicates = self.reject_duplicates + for item in self.keyword_args: + if item.is_dict_literal: + # process items in order + items = ((key.constant_result, value.constant_result) + for key, value in item.key_value_pairs) + else: + items = item.constant_result.iteritems() + + for key, value in items: + if reject_duplicates and key in result: + raise ValueError("duplicate keyword argument found: %s" % key) + result[key] = value + + self.constant_result = result + + def compile_time_value(self, denv): + result = {} + reject_duplicates = self.reject_duplicates + for item in self.keyword_args: + if item.is_dict_literal: + # process items in order + items = [(key.compile_time_value(denv), value.compile_time_value(denv)) + for key, value in item.key_value_pairs] + else: + items = item.compile_time_value(denv).iteritems() + + try: + for key, value in items: + if reject_duplicates and key in result: + raise ValueError("duplicate keyword argument found: %s" % key) + result[key] = value + except Exception as e: + self.compile_time_value_error(e) + return result + + def type_dependencies(self, env): + return () + + def infer_type(self, env): + return dict_type + + def analyse_types(self, env): self.keyword_args = [ - arg.analyse_types(env).coerce_to_pyobject(env).as_none_safe_node( - # FIXME: CPython's error message starts with the runtime function name - 'argument after ** must be a mapping, not NoneType') - for arg in self.keyword_args - ] - - return self - - def may_be_none(self): - return False - - gil_message = "Constructing Python dict" - - def generate_evaluation_code(self, code): - code.mark_pos(self.pos) - self.allocate_temp_result(code) - - args = iter(self.keyword_args) - item = next(args) - item.generate_evaluation_code(code) - if item.type is not dict_type: - # CPython supports calling functions with non-dicts, so do we - code.putln('if (likely(PyDict_CheckExact(%s))) {' % - item.py_result()) - - if item.is_dict_literal: - item.make_owned_reference(code) - code.putln("%s = %s;" % (self.result(), item.py_result())) - item.generate_post_assignment_code(code) - else: - code.putln("%s = PyDict_Copy(%s); %s" % ( - self.result(), - item.py_result(), - code.error_goto_if_null(self.result(), item.pos))) - code.put_gotref(self.result()) - item.generate_disposal_code(code) - - if item.type is not dict_type: - code.putln('} else {') - code.putln("%s = PyObject_CallFunctionObjArgs((PyObject*)&PyDict_Type, %s, NULL); %s" % ( - self.result(), - item.py_result(), - code.error_goto_if_null(self.result(), self.pos))) - code.put_gotref(self.py_result()) - item.generate_disposal_code(code) - code.putln('}') - item.free_temps(code) - - helpers = set() - for item in args: - if item.is_dict_literal: - # inline update instead of creating an intermediate dict - for arg in item.key_value_pairs: - arg.generate_evaluation_code(code) - if self.reject_duplicates: - code.putln("if (unlikely(PyDict_Contains(%s, %s))) {" % ( - self.result(), - arg.key.py_result())) - helpers.add("RaiseDoubleKeywords") - # FIXME: find out function name at runtime! - code.putln('__Pyx_RaiseDoubleKeywordsError("function", %s); %s' % ( - arg.key.py_result(), - code.error_goto(self.pos))) - code.putln("}") - code.put_error_if_neg(arg.key.pos, "PyDict_SetItem(%s, %s, %s)" % ( - self.result(), - arg.key.py_result(), - arg.value.py_result())) - arg.generate_disposal_code(code) - arg.free_temps(code) - else: - item.generate_evaluation_code(code) - if self.reject_duplicates: - # merge mapping into kwdict one by one as we need to check for duplicates - helpers.add("MergeKeywords") - code.put_error_if_neg(item.pos, "__Pyx_MergeKeywords(%s, %s)" % ( - self.result(), item.py_result())) - else: - # simple case, just add all entries - helpers.add("RaiseMappingExpected") - code.putln("if (unlikely(PyDict_Update(%s, %s) < 0)) {" % ( - self.result(), item.py_result())) - code.putln("if (PyErr_ExceptionMatches(PyExc_AttributeError)) " - "__Pyx_RaiseMappingExpectedError(%s);" % item.py_result()) - code.putln(code.error_goto(item.pos)) - code.putln("}") - item.generate_disposal_code(code) - item.free_temps(code) - - for helper in sorted(helpers): - code.globalstate.use_utility_code(UtilityCode.load_cached(helper, "FunctionArguments.c")) - - def annotate(self, code): - for item in self.keyword_args: - item.annotate(code) - - + arg.analyse_types(env).coerce_to_pyobject(env).as_none_safe_node( + # FIXME: CPython's error message starts with the runtime function name + 'argument after ** must be a mapping, not NoneType') + for arg in self.keyword_args + ] + + return self + + def may_be_none(self): + return False + + gil_message = "Constructing Python dict" + + def generate_evaluation_code(self, code): + code.mark_pos(self.pos) + self.allocate_temp_result(code) + + args = iter(self.keyword_args) + item = next(args) + item.generate_evaluation_code(code) + if item.type is not dict_type: + # CPython supports calling functions with non-dicts, so do we + code.putln('if (likely(PyDict_CheckExact(%s))) {' % + item.py_result()) + + if item.is_dict_literal: + item.make_owned_reference(code) + code.putln("%s = %s;" % (self.result(), item.py_result())) + item.generate_post_assignment_code(code) + else: + code.putln("%s = PyDict_Copy(%s); %s" % ( + self.result(), + item.py_result(), + code.error_goto_if_null(self.result(), item.pos))) + code.put_gotref(self.result()) + item.generate_disposal_code(code) + + if item.type is not dict_type: + code.putln('} else {') + code.putln("%s = PyObject_CallFunctionObjArgs((PyObject*)&PyDict_Type, %s, NULL); %s" % ( + self.result(), + item.py_result(), + code.error_goto_if_null(self.result(), self.pos))) + code.put_gotref(self.py_result()) + item.generate_disposal_code(code) + code.putln('}') + item.free_temps(code) + + helpers = set() + for item in args: + if item.is_dict_literal: + # inline update instead of creating an intermediate dict + for arg in item.key_value_pairs: + arg.generate_evaluation_code(code) + if self.reject_duplicates: + code.putln("if (unlikely(PyDict_Contains(%s, %s))) {" % ( + self.result(), + arg.key.py_result())) + helpers.add("RaiseDoubleKeywords") + # FIXME: find out function name at runtime! + code.putln('__Pyx_RaiseDoubleKeywordsError("function", %s); %s' % ( + arg.key.py_result(), + code.error_goto(self.pos))) + code.putln("}") + code.put_error_if_neg(arg.key.pos, "PyDict_SetItem(%s, %s, %s)" % ( + self.result(), + arg.key.py_result(), + arg.value.py_result())) + arg.generate_disposal_code(code) + arg.free_temps(code) + else: + item.generate_evaluation_code(code) + if self.reject_duplicates: + # merge mapping into kwdict one by one as we need to check for duplicates + helpers.add("MergeKeywords") + code.put_error_if_neg(item.pos, "__Pyx_MergeKeywords(%s, %s)" % ( + self.result(), item.py_result())) + else: + # simple case, just add all entries + helpers.add("RaiseMappingExpected") + code.putln("if (unlikely(PyDict_Update(%s, %s) < 0)) {" % ( + self.result(), item.py_result())) + code.putln("if (PyErr_ExceptionMatches(PyExc_AttributeError)) " + "__Pyx_RaiseMappingExpectedError(%s);" % item.py_result()) + code.putln(code.error_goto(item.pos)) + code.putln("}") + item.generate_disposal_code(code) + item.free_temps(code) + + for helper in sorted(helpers): + code.globalstate.use_utility_code(UtilityCode.load_cached(helper, "FunctionArguments.c")) + + def annotate(self, code): + for item in self.keyword_args: + item.annotate(code) + + class AttributeNode(ExprNode): # obj.attribute # @@ -6791,7 +6791,7 @@ class AttributeNode(ExprNode): needs_none_check = True is_memslice_transpose = False is_special_lookup = False - is_py_attr = 0 + is_py_attr = 0 def as_cython_attribute(self): if (isinstance(self.obj, NameNode) and @@ -6832,7 +6832,7 @@ class AttributeNode(ExprNode): obj = self.obj.compile_time_value(denv) try: return getattr(obj, attr) - except Exception as e: + except Exception as e: self.compile_time_value_error(e) def type_dependencies(self, env): @@ -6847,7 +6847,7 @@ class AttributeNode(ExprNode): return PyrexTypes.CPtrType(node.entry.type) else: return node.entry.type - node = self.analyse_as_type_attribute(env) + node = self.analyse_as_type_attribute(env) if node is not None: return node.entry.type obj_type = self.obj.infer_type(env) @@ -6857,10 +6857,10 @@ class AttributeNode(ExprNode): # builtin types cannot be inferred as C functions as # that would prevent their use as bound methods return py_object_type - elif self.entry and self.entry.is_cmethod: - # special case: bound methods should not be inferred - # as their unbound method types - return py_object_type + elif self.entry and self.entry.is_cmethod: + # special case: bound methods should not be inferred + # as their unbound method types + return py_object_type return self.type def analyse_target_declaration(self, env): @@ -6878,7 +6878,7 @@ class AttributeNode(ExprNode): self.initialized_check = env.directives['initializedcheck'] node = self.analyse_as_cimported_attribute_node(env, target) if node is None and not target: - node = self.analyse_as_type_attribute(env) + node = self.analyse_as_type_attribute(env) if node is None: node = self.analyse_as_ordinary_attribute_node(env, target) assert node is not None @@ -6905,7 +6905,7 @@ class AttributeNode(ExprNode): return self return None - def analyse_as_type_attribute(self, env): + def analyse_as_type_attribute(self, env): # Try to interpret this as a reference to an unbound # C method of an extension type or builtin type. If successful, # creates a corresponding NameNode and returns it, otherwise @@ -6913,49 +6913,49 @@ class AttributeNode(ExprNode): if self.obj.is_string_literal: return type = self.obj.analyse_as_type(env) - if type: - if type.is_extension_type or type.is_builtin_type or type.is_cpp_class: - entry = type.scope.lookup_here(self.attribute) - if entry and (entry.is_cmethod or type.is_cpp_class and entry.type.is_cfunction): - if type.is_builtin_type: - if not self.is_called: - # must handle this as Python object - return None - ubcm_entry = entry - else: - # Create a temporary entry describing the C method - # as an ordinary function. - if entry.func_cname and not hasattr(entry.type, 'op_arg_struct'): - cname = entry.func_cname - if entry.type.is_static_method or ( - env.parent_scope and env.parent_scope.is_cpp_class_scope): - ctype = entry.type - elif type.is_cpp_class: - error(self.pos, "%s not a static member of %s" % (entry.name, type)) - ctype = PyrexTypes.error_type - else: - # Fix self type. - ctype = copy.copy(entry.type) - ctype.args = ctype.args[:] - ctype.args[0] = PyrexTypes.CFuncTypeArg('self', type, 'self', None) - else: - cname = "%s->%s" % (type.vtabptr_cname, entry.cname) + if type: + if type.is_extension_type or type.is_builtin_type or type.is_cpp_class: + entry = type.scope.lookup_here(self.attribute) + if entry and (entry.is_cmethod or type.is_cpp_class and entry.type.is_cfunction): + if type.is_builtin_type: + if not self.is_called: + # must handle this as Python object + return None + ubcm_entry = entry + else: + # Create a temporary entry describing the C method + # as an ordinary function. + if entry.func_cname and not hasattr(entry.type, 'op_arg_struct'): + cname = entry.func_cname + if entry.type.is_static_method or ( + env.parent_scope and env.parent_scope.is_cpp_class_scope): + ctype = entry.type + elif type.is_cpp_class: + error(self.pos, "%s not a static member of %s" % (entry.name, type)) + ctype = PyrexTypes.error_type + else: + # Fix self type. + ctype = copy.copy(entry.type) + ctype.args = ctype.args[:] + ctype.args[0] = PyrexTypes.CFuncTypeArg('self', type, 'self', None) + else: + cname = "%s->%s" % (type.vtabptr_cname, entry.cname) ctype = entry.type - ubcm_entry = Symtab.Entry(entry.name, cname, ctype) - ubcm_entry.is_cfunction = 1 - ubcm_entry.func_cname = entry.func_cname - ubcm_entry.is_unbound_cmethod = 1 - ubcm_entry.scope = entry.scope - return self.as_name_node(env, ubcm_entry, target=False) - elif type.is_enum: - if self.attribute in type.values: - for entry in type.entry.enum_values: - if entry.name == self.attribute: - return self.as_name_node(env, entry, target=False) + ubcm_entry = Symtab.Entry(entry.name, cname, ctype) + ubcm_entry.is_cfunction = 1 + ubcm_entry.func_cname = entry.func_cname + ubcm_entry.is_unbound_cmethod = 1 + ubcm_entry.scope = entry.scope + return self.as_name_node(env, ubcm_entry, target=False) + elif type.is_enum: + if self.attribute in type.values: + for entry in type.entry.enum_values: + if entry.name == self.attribute: + return self.as_name_node(env, entry, target=False) else: - error(self.pos, "%s not a known value of %s" % (self.attribute, type)) - else: - error(self.pos, "%s not a known value of %s" % (self.attribute, type)) + error(self.pos, "%s not a known value of %s" % (self.attribute, type)) + else: + error(self.pos, "%s not a known value of %s" % (self.attribute, type)) return None def analyse_as_type(self, env): @@ -7036,23 +7036,23 @@ class AttributeNode(ExprNode): self.op = "->" elif obj_type.is_extension_type or obj_type.is_builtin_type: self.op = "->" - elif obj_type.is_reference and obj_type.is_fake_reference: - self.op = "->" + elif obj_type.is_reference and obj_type.is_fake_reference: + self.op = "->" else: self.op = "." if obj_type.has_attributes: if obj_type.attributes_known(): - entry = obj_type.scope.lookup_here(self.attribute) - if obj_type.is_memoryviewslice and not entry: + entry = obj_type.scope.lookup_here(self.attribute) + if obj_type.is_memoryviewslice and not entry: if self.attribute == 'T': self.is_memslice_transpose = True self.is_temp = True self.use_managed_ref = True - self.type = self.obj.type.transpose(self.pos) + self.type = self.obj.type.transpose(self.pos) return else: obj_type.declare_attribute(self.attribute, env, self.pos) - entry = obj_type.scope.lookup_here(self.attribute) + entry = obj_type.scope.lookup_here(self.attribute) if entry and entry.is_member: entry = None else: @@ -7156,7 +7156,7 @@ class AttributeNode(ExprNode): def is_lvalue(self): if self.obj: - return True + return True else: return NameNode.is_lvalue(self) @@ -7231,7 +7231,7 @@ class AttributeNode(ExprNode): return code.putln("%s = %s;" % (self.result(), self.obj.result())) - code.put_incref_memoryviewslice(self.result(), have_gil=True) + code.put_incref_memoryviewslice(self.result(), have_gil=True) T = "__pyx_memslice_transpose(&%s) == 0" code.putln(code.error_goto_if(T % self.result(), self.pos)) @@ -7245,24 +7245,24 @@ class AttributeNode(ExprNode): else: # result_code contains what is needed, but we may need to insert # a check and raise an exception - if self.obj.type and self.obj.type.is_extension_type: + if self.obj.type and self.obj.type.is_extension_type: pass - elif self.entry and self.entry.is_cmethod: + elif self.entry and self.entry.is_cmethod: # C method implemented as function call with utility code - code.globalstate.use_entry_utility_code(self.entry) + code.globalstate.use_entry_utility_code(self.entry) def generate_disposal_code(self, code): if self.is_temp and self.type.is_memoryviewslice and self.is_memslice_transpose: # mirror condition for putting the memview incref here: - code.put_xdecref_memoryviewslice( - self.result(), have_gil=True) - code.putln("%s.memview = NULL;" % self.result()) - code.putln("%s.data = NULL;" % self.result()) + code.put_xdecref_memoryviewslice( + self.result(), have_gil=True) + code.putln("%s.memview = NULL;" % self.result()) + code.putln("%s.data = NULL;" % self.result()) else: ExprNode.generate_disposal_code(self, code) - def generate_assignment_code(self, rhs, code, overloaded_assignment=False, - exception_check=None, exception_value=None): + def generate_assignment_code(self, rhs, code, overloaded_assignment=False, + exception_check=None, exception_value=None): self.obj.generate_evaluation_code(code) if self.is_py_attr: code.globalstate.use_utility_code( @@ -7333,14 +7333,14 @@ class AttributeNode(ExprNode): # #------------------------------------------------------------------- -class StarredUnpackingNode(ExprNode): +class StarredUnpackingNode(ExprNode): # A starred expression like "*a" # - # This is only allowed in sequence assignment or construction such as + # This is only allowed in sequence assignment or construction such as # # a, *b = (1,2,3,4) => a = 1 ; b = [2,3,4] # - # and will be special cased during type analysis (or generate an error + # and will be special cased during type analysis (or generate an error # if it's found at unexpected places). # # target ExprNode @@ -7349,22 +7349,22 @@ class StarredUnpackingNode(ExprNode): is_starred = 1 type = py_object_type is_temp = 1 - starred_expr_allowed_here = False + starred_expr_allowed_here = False def __init__(self, pos, target): - ExprNode.__init__(self, pos, target=target) + ExprNode.__init__(self, pos, target=target) def analyse_declarations(self, env): - if not self.starred_expr_allowed_here: - error(self.pos, "starred expression is not allowed here") + if not self.starred_expr_allowed_here: + error(self.pos, "starred expression is not allowed here") self.target.analyse_declarations(env) - def infer_type(self, env): - return self.target.infer_type(env) - + def infer_type(self, env): + return self.target.infer_type(env) + def analyse_types(self, env): - if not self.starred_expr_allowed_here: - error(self.pos, "starred expression is not allowed here") + if not self.starred_expr_allowed_here: + error(self.pos, "starred expression is not allowed here") self.target = self.target.analyse_types(env) self.type = self.target.type return self @@ -7423,9 +7423,9 @@ class SequenceNode(ExprNode): arg.analyse_target_declaration(env) def analyse_types(self, env, skip_children=False): - for i, arg in enumerate(self.args): - if not skip_children: - arg = arg.analyse_types(env) + for i, arg in enumerate(self.args): + if not skip_children: + arg = arg.analyse_types(env) self.args[i] = arg.coerce_to_pyobject(env) if self.mult_factor: self.mult_factor = self.mult_factor.analyse_types(env) @@ -7435,49 +7435,49 @@ class SequenceNode(ExprNode): # not setting self.type here, subtypes do this return self - def coerce_to_ctuple(self, dst_type, env): - if self.type == dst_type: - return self - assert not self.mult_factor - if len(self.args) != dst_type.size: - error(self.pos, "trying to coerce sequence to ctuple of wrong length, expected %d, got %d" % ( - dst_type.size, len(self.args))) - coerced_args = [arg.coerce_to(type, env) for arg, type in zip(self.args, dst_type.components)] - return TupleNode(self.pos, args=coerced_args, type=dst_type, is_temp=True) - - def _create_merge_node_if_necessary(self, env): - self._flatten_starred_args() - if not any(arg.is_starred for arg in self.args): - return self - # convert into MergedSequenceNode by building partial sequences - args = [] - values = [] - for arg in self.args: - if arg.is_starred: - if values: - args.append(TupleNode(values[0].pos, args=values).analyse_types(env, skip_children=True)) - values = [] - args.append(arg.target) - else: - values.append(arg) - if values: - args.append(TupleNode(values[0].pos, args=values).analyse_types(env, skip_children=True)) - node = MergedSequenceNode(self.pos, args, self.type) - if self.mult_factor: - node = binop_node( - self.pos, '*', node, self.mult_factor.coerce_to_pyobject(env), - inplace=True, type=self.type, is_temp=True) - return node - - def _flatten_starred_args(self): - args = [] - for arg in self.args: - if arg.is_starred and arg.target.is_sequence_constructor and not arg.target.mult_factor: - args.extend(arg.target.args) - else: - args.append(arg) - self.args[:] = args - + def coerce_to_ctuple(self, dst_type, env): + if self.type == dst_type: + return self + assert not self.mult_factor + if len(self.args) != dst_type.size: + error(self.pos, "trying to coerce sequence to ctuple of wrong length, expected %d, got %d" % ( + dst_type.size, len(self.args))) + coerced_args = [arg.coerce_to(type, env) for arg, type in zip(self.args, dst_type.components)] + return TupleNode(self.pos, args=coerced_args, type=dst_type, is_temp=True) + + def _create_merge_node_if_necessary(self, env): + self._flatten_starred_args() + if not any(arg.is_starred for arg in self.args): + return self + # convert into MergedSequenceNode by building partial sequences + args = [] + values = [] + for arg in self.args: + if arg.is_starred: + if values: + args.append(TupleNode(values[0].pos, args=values).analyse_types(env, skip_children=True)) + values = [] + args.append(arg.target) + else: + values.append(arg) + if values: + args.append(TupleNode(values[0].pos, args=values).analyse_types(env, skip_children=True)) + node = MergedSequenceNode(self.pos, args, self.type) + if self.mult_factor: + node = binop_node( + self.pos, '*', node, self.mult_factor.coerce_to_pyobject(env), + inplace=True, type=self.type, is_temp=True) + return node + + def _flatten_starred_args(self): + args = [] + for arg in self.args: + if arg.is_starred and arg.target.is_sequence_constructor and not arg.target.mult_factor: + args.extend(arg.target.args) + else: + args.append(arg) + self.args[:] = args + def may_be_none(self): return False @@ -7490,11 +7490,11 @@ class SequenceNode(ExprNode): for i, arg in enumerate(self.args): arg = self.args[i] = arg.analyse_target_types(env) if arg.is_starred: - if not arg.type.assignable_from(list_type): + if not arg.type.assignable_from(list_type): error(arg.pos, "starred target must have Python object (list) type") if arg.type is py_object_type: - arg.type = list_type + arg.type = list_type unpacked_item = PyTempNode(self.pos, env) coerced_unpacked_item = unpacked_item.coerce_to(arg.type, env) if unpacked_item is not coerced_unpacked_item: @@ -7517,31 +7517,31 @@ class SequenceNode(ExprNode): mult_factor = self.mult_factor if mult_factor.type.is_int: c_mult = mult_factor.result() - if (isinstance(mult_factor.constant_result, _py_int_types) and - mult_factor.constant_result > 0): + if (isinstance(mult_factor.constant_result, _py_int_types) and + mult_factor.constant_result > 0): size_factor = ' * %s' % mult_factor.constant_result - elif mult_factor.type.signed: - size_factor = ' * ((%s<0) ? 0:%s)' % (c_mult, c_mult) + elif mult_factor.type.signed: + size_factor = ' * ((%s<0) ? 0:%s)' % (c_mult, c_mult) else: - size_factor = ' * (%s)' % (c_mult,) + size_factor = ' * (%s)' % (c_mult,) - if self.type is tuple_type and (self.is_literal or self.slow) and not c_mult: + if self.type is tuple_type and (self.is_literal or self.slow) and not c_mult: # use PyTuple_Pack() to avoid generating huge amounts of one-time code code.putln('%s = PyTuple_Pack(%d, %s); %s' % ( target, len(self.args), - ', '.join(arg.py_result() for arg in self.args), + ', '.join(arg.py_result() for arg in self.args), code.error_goto_if_null(target, self.pos))) code.put_gotref(target) - elif self.type.is_ctuple: - for i, arg in enumerate(self.args): - code.putln("%s.f%s = %s;" % ( - target, i, arg.result())) + elif self.type.is_ctuple: + for i, arg in enumerate(self.args): + code.putln("%s.f%s = %s;" % ( + target, i, arg.result())) else: # build the tuple/list step by step, potentially multiplying it as we go - if self.type is list_type: + if self.type is list_type: create_func, set_item_func = 'PyList_New', 'PyList_SET_ITEM' - elif self.type is tuple_type: + elif self.type is tuple_type: create_func, set_item_func = 'PyTuple_New', 'PyTuple_SET_ITEM' else: raise InternalError("sequence packing for unexpected type %s" % self.type) @@ -7569,11 +7569,11 @@ class SequenceNode(ExprNode): else: offset = '' - for i in range(arg_count): + for i in range(arg_count): arg = self.args[i] if c_mult or not arg.result_in_temp(): code.put_incref(arg.result(), arg.ctype()) - code.put_giveref(arg.py_result()) + code.put_giveref(arg.py_result()) code.putln("%s(%s, %s, %s);" % ( set_item_func, target, @@ -7598,7 +7598,7 @@ class SequenceNode(ExprNode): def generate_subexpr_disposal_code(self, code): if self.mult_factor and self.mult_factor.type.is_int: super(SequenceNode, self).generate_subexpr_disposal_code(code) - elif self.type is tuple_type and (self.is_literal or self.slow): + elif self.type is tuple_type and (self.is_literal or self.slow): super(SequenceNode, self).generate_subexpr_disposal_code(code) else: # We call generate_post_assignment_code here instead @@ -7611,8 +7611,8 @@ class SequenceNode(ExprNode): if self.mult_factor: self.mult_factor.generate_disposal_code(code) - def generate_assignment_code(self, rhs, code, overloaded_assignment=False, - exception_check=None, exception_value=None): + def generate_assignment_code(self, rhs, code, overloaded_assignment=False, + exception_check=None, exception_value=None): if self.starred_assignment: self.generate_starred_assignment_code(rhs, code) else: @@ -7685,7 +7685,7 @@ class SequenceNode(ExprNode): code.putln(code.error_goto(self.pos)) code.putln("}") - code.putln("#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS") + code.putln("#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS") # unpack items from list/tuple in unrolled loop (can't fail) if len(sequence_types) == 2: code.putln("if (likely(Py%s_CheckExact(sequence))) {" % sequence_types[0]) @@ -7883,7 +7883,7 @@ class SequenceNode(ExprNode): code.put_decref(target_list, py_object_type) code.putln('%s = %s; %s = NULL;' % (target_list, sublist_temp, sublist_temp)) code.putln('#else') - code.putln('(void)%s;' % sublist_temp) # avoid warning about unused variable + code.putln('(void)%s;' % sublist_temp) # avoid warning about unused variable code.funcstate.release_temp(sublist_temp) code.putln('#endif') @@ -7908,82 +7908,82 @@ class TupleNode(SequenceNode): gil_message = "Constructing Python tuple" - def infer_type(self, env): - if self.mult_factor or not self.args: - return tuple_type - arg_types = [arg.infer_type(env) for arg in self.args] + def infer_type(self, env): + if self.mult_factor or not self.args: + return tuple_type + arg_types = [arg.infer_type(env) for arg in self.args] if any(type.is_pyobject or type.is_memoryviewslice or type.is_unspecified or type.is_fused for type in arg_types): - return tuple_type + return tuple_type return env.declare_tuple_type(self.pos, arg_types).type - + def analyse_types(self, env, skip_children=False): if len(self.args) == 0: - self.is_temp = False - self.is_literal = True - return self - - if not skip_children: - for i, arg in enumerate(self.args): - if arg.is_starred: - arg.starred_expr_allowed_here = True - self.args[i] = arg.analyse_types(env) - if (not self.mult_factor and + self.is_temp = False + self.is_literal = True + return self + + if not skip_children: + for i, arg in enumerate(self.args): + if arg.is_starred: + arg.starred_expr_allowed_here = True + self.args[i] = arg.analyse_types(env) + if (not self.mult_factor and not any((arg.is_starred or arg.type.is_pyobject or arg.type.is_memoryviewslice or arg.type.is_fused) for arg in self.args)): - self.type = env.declare_tuple_type(self.pos, (arg.type for arg in self.args)).type - self.is_temp = 1 - return self - - node = SequenceNode.analyse_types(self, env, skip_children=True) - node = node._create_merge_node_if_necessary(env) - if not node.is_sequence_constructor: - return node - - if not all(child.is_literal for child in node.args): - return node - if not node.mult_factor or ( - node.mult_factor.is_literal and - isinstance(node.mult_factor.constant_result, _py_int_types)): + self.type = env.declare_tuple_type(self.pos, (arg.type for arg in self.args)).type + self.is_temp = 1 + return self + + node = SequenceNode.analyse_types(self, env, skip_children=True) + node = node._create_merge_node_if_necessary(env) + if not node.is_sequence_constructor: + return node + + if not all(child.is_literal for child in node.args): + return node + if not node.mult_factor or ( + node.mult_factor.is_literal and + isinstance(node.mult_factor.constant_result, _py_int_types)): node.is_temp = False node.is_literal = True else: - if not node.mult_factor.type.is_pyobject: - node.mult_factor = node.mult_factor.coerce_to_pyobject(env) - node.is_temp = True - node.is_partly_literal = True + if not node.mult_factor.type.is_pyobject: + node.mult_factor = node.mult_factor.coerce_to_pyobject(env) + node.is_temp = True + node.is_partly_literal = True return node - def analyse_as_type(self, env): - # ctuple type - if not self.args: - return None - item_types = [arg.analyse_as_type(env) for arg in self.args] - if any(t is None for t in item_types): - return None - entry = env.declare_tuple_type(self.pos, item_types) - return entry.type - - def coerce_to(self, dst_type, env): - if self.type.is_ctuple: - if dst_type.is_ctuple and self.type.size == dst_type.size: - return self.coerce_to_ctuple(dst_type, env) - elif dst_type is tuple_type or dst_type is py_object_type: - coerced_args = [arg.coerce_to_pyobject(env) for arg in self.args] - return TupleNode(self.pos, args=coerced_args, type=tuple_type, is_temp=1).analyse_types(env, skip_children=True) - else: - return self.coerce_to_pyobject(env).coerce_to(dst_type, env) - elif dst_type.is_ctuple and not self.mult_factor: - return self.coerce_to_ctuple(dst_type, env) - else: - return SequenceNode.coerce_to(self, dst_type, env) - - def as_list(self): - t = ListNode(self.pos, args=self.args, mult_factor=self.mult_factor) - if isinstance(self.constant_result, tuple): - t.constant_result = list(self.constant_result) - return t - + def analyse_as_type(self, env): + # ctuple type + if not self.args: + return None + item_types = [arg.analyse_as_type(env) for arg in self.args] + if any(t is None for t in item_types): + return None + entry = env.declare_tuple_type(self.pos, item_types) + return entry.type + + def coerce_to(self, dst_type, env): + if self.type.is_ctuple: + if dst_type.is_ctuple and self.type.size == dst_type.size: + return self.coerce_to_ctuple(dst_type, env) + elif dst_type is tuple_type or dst_type is py_object_type: + coerced_args = [arg.coerce_to_pyobject(env) for arg in self.args] + return TupleNode(self.pos, args=coerced_args, type=tuple_type, is_temp=1).analyse_types(env, skip_children=True) + else: + return self.coerce_to_pyobject(env).coerce_to(dst_type, env) + elif dst_type.is_ctuple and not self.mult_factor: + return self.coerce_to_ctuple(dst_type, env) + else: + return SequenceNode.coerce_to(self, dst_type, env) + + def as_list(self): + t = ListNode(self.pos, args=self.args, mult_factor=self.mult_factor) + if isinstance(self.constant_result, tuple): + t.constant_result = list(self.constant_result) + return t + def is_simple(self): # either temp or constant => always simple return True @@ -8006,7 +8006,7 @@ class TupleNode(SequenceNode): values = self.compile_time_value_list(denv) try: return tuple(values) - except Exception as e: + except Exception as e: self.compile_time_value_error(e) def generate_operation_code(self, code): @@ -8015,16 +8015,16 @@ class TupleNode(SequenceNode): return if self.is_literal or self.is_partly_literal: - # The "mult_factor" is part of the deduplication if it is also constant, i.e. when - # we deduplicate the multiplied result. Otherwise, only deduplicate the constant part. - dedup_key = make_dedup_key(self.type, [self.mult_factor if self.is_literal else None] + self.args) - tuple_target = code.get_py_const(py_object_type, 'tuple', cleanup_level=2, dedup_key=dedup_key) - const_code = code.get_cached_constants_writer(tuple_target) - if const_code is not None: - # constant is not yet initialised - const_code.mark_pos(self.pos) - self.generate_sequence_packing_code(const_code, tuple_target, plain=not self.is_literal) - const_code.put_giveref(tuple_target) + # The "mult_factor" is part of the deduplication if it is also constant, i.e. when + # we deduplicate the multiplied result. Otherwise, only deduplicate the constant part. + dedup_key = make_dedup_key(self.type, [self.mult_factor if self.is_literal else None] + self.args) + tuple_target = code.get_py_const(py_object_type, 'tuple', cleanup_level=2, dedup_key=dedup_key) + const_code = code.get_cached_constants_writer(tuple_target) + if const_code is not None: + # constant is not yet initialised + const_code.mark_pos(self.pos) + self.generate_sequence_packing_code(const_code, tuple_target, plain=not self.is_literal) + const_code.put_giveref(tuple_target) if self.is_literal: self.result_code = tuple_target else: @@ -8034,7 +8034,7 @@ class TupleNode(SequenceNode): )) code.put_gotref(self.py_result()) else: - self.type.entry.used = True + self.type.entry.used = True self.generate_sequence_packing_code(code) @@ -8054,13 +8054,13 @@ class ListNode(SequenceNode): return () def infer_type(self, env): - # TODO: Infer non-object list arrays. + # TODO: Infer non-object list arrays. return list_type def analyse_expressions(self, env): - for arg in self.args: - if arg.is_starred: - arg.starred_expr_allowed_here = True + for arg in self.args: + if arg.is_starred: + arg.starred_expr_allowed_here = True node = SequenceNode.analyse_expressions(self, env) return node.coerce_to_pyobject(env) @@ -8071,7 +8071,7 @@ class ListNode(SequenceNode): node.obj_conversion_errors = errors if env.is_module_scope: self.in_module_scope = True - node = node._create_merge_node_if_necessary(env) + node = node._create_merge_node_if_necessary(env) return node def coerce_to(self, dst_type, env): @@ -8081,31 +8081,31 @@ class ListNode(SequenceNode): self.obj_conversion_errors = [] if not self.type.subtype_of(dst_type): error(self.pos, "Cannot coerce list to type '%s'" % dst_type) - elif (dst_type.is_array or dst_type.is_ptr) and dst_type.base_type is not PyrexTypes.c_void_type: - array_length = len(self.args) - if self.mult_factor: - if isinstance(self.mult_factor.constant_result, _py_int_types): - if self.mult_factor.constant_result <= 0: - error(self.pos, "Cannot coerce non-positively multiplied list to '%s'" % dst_type) - else: - array_length *= self.mult_factor.constant_result - else: - error(self.pos, "Cannot coerce dynamically multiplied list to '%s'" % dst_type) + elif (dst_type.is_array or dst_type.is_ptr) and dst_type.base_type is not PyrexTypes.c_void_type: + array_length = len(self.args) + if self.mult_factor: + if isinstance(self.mult_factor.constant_result, _py_int_types): + if self.mult_factor.constant_result <= 0: + error(self.pos, "Cannot coerce non-positively multiplied list to '%s'" % dst_type) + else: + array_length *= self.mult_factor.constant_result + else: + error(self.pos, "Cannot coerce dynamically multiplied list to '%s'" % dst_type) base_type = dst_type.base_type - self.type = PyrexTypes.CArrayType(base_type, array_length) + self.type = PyrexTypes.CArrayType(base_type, array_length) for i in range(len(self.original_args)): arg = self.args[i] if isinstance(arg, CoerceToPyTypeNode): arg = arg.arg self.args[i] = arg.coerce_to(base_type, env) - elif dst_type.is_cpp_class: - # TODO(robertwb): Avoid object conversion for vector/list/set. - return TypecastNode(self.pos, operand=self, type=PyrexTypes.py_object_type).coerce_to(dst_type, env) - elif self.mult_factor: - error(self.pos, "Cannot coerce multiplied list to '%s'" % dst_type) + elif dst_type.is_cpp_class: + # TODO(robertwb): Avoid object conversion for vector/list/set. + return TypecastNode(self.pos, operand=self, type=PyrexTypes.py_object_type).coerce_to(dst_type, env) + elif self.mult_factor: + error(self.pos, "Cannot coerce multiplied list to '%s'" % dst_type) elif dst_type.is_struct: if len(self.args) > len(dst_type.scope.var_entries): - error(self.pos, "Too many members for '%s'" % dst_type) + error(self.pos, "Too many members for '%s'" % dst_type) else: if len(self.args) < len(dst_type.scope.var_entries): warning(self.pos, "Too few members for '%s'" % dst_type, 1) @@ -8114,16 +8114,16 @@ class ListNode(SequenceNode): arg = arg.arg self.args[i] = arg.coerce_to(member.type, env) self.type = dst_type - elif dst_type.is_ctuple: - return self.coerce_to_ctuple(dst_type, env) + elif dst_type.is_ctuple: + return self.coerce_to_ctuple(dst_type, env) else: self.type = error_type error(self.pos, "Cannot coerce list to type '%s'" % dst_type) return self - def as_list(self): # dummy for compatibility with TupleNode - return self - + def as_list(self): # dummy for compatibility with TupleNode + return self + def as_tuple(self): t = TupleNode(self.pos, args=self.args, mult_factor=self.mult_factor) if isinstance(self.constant_result, list): @@ -8146,7 +8146,7 @@ class ListNode(SequenceNode): def calculate_constant_result(self): if self.mult_factor: - raise ValueError() # may exceed the compile time memory + raise ValueError() # may exceed the compile time memory self.constant_result = [ arg.constant_result for arg in self.args] @@ -8162,36 +8162,36 @@ class ListNode(SequenceNode): report_error(err) self.generate_sequence_packing_code(code) elif self.type.is_array: - if self.mult_factor: - code.putln("{") - code.putln("Py_ssize_t %s;" % Naming.quick_temp_cname) - code.putln("for ({i} = 0; {i} < {count}; {i}++) {{".format( - i=Naming.quick_temp_cname, count=self.mult_factor.result())) - offset = '+ (%d * %s)' % (len(self.args), Naming.quick_temp_cname) - else: - offset = '' + if self.mult_factor: + code.putln("{") + code.putln("Py_ssize_t %s;" % Naming.quick_temp_cname) + code.putln("for ({i} = 0; {i} < {count}; {i}++) {{".format( + i=Naming.quick_temp_cname, count=self.mult_factor.result())) + offset = '+ (%d * %s)' % (len(self.args), Naming.quick_temp_cname) + else: + offset = '' for i, arg in enumerate(self.args): - if arg.type.is_array: - code.globalstate.use_utility_code(UtilityCode.load_cached("IncludeStringH", "StringTools.c")) - code.putln("memcpy(&(%s[%s%s]), %s, sizeof(%s[0]));" % ( - self.result(), i, offset, - arg.result(), self.result() - )) - else: - code.putln("%s[%s%s] = %s;" % ( - self.result(), - i, - offset, - arg.result())) - if self.mult_factor: - code.putln("}") - code.putln("}") + if arg.type.is_array: + code.globalstate.use_utility_code(UtilityCode.load_cached("IncludeStringH", "StringTools.c")) + code.putln("memcpy(&(%s[%s%s]), %s, sizeof(%s[0]));" % ( + self.result(), i, offset, + arg.result(), self.result() + )) + else: + code.putln("%s[%s%s] = %s;" % ( + self.result(), + i, + offset, + arg.result())) + if self.mult_factor: + code.putln("}") + code.putln("}") elif self.type.is_struct: for arg, member in zip(self.args, self.type.scope.var_entries): code.putln("%s.%s = %s;" % ( - self.result(), - member.cname, - arg.result())) + self.result(), + member.cname, + arg.result())) else: raise InternalError("List type never specified") @@ -8416,228 +8416,228 @@ class DictComprehensionAppendNode(ComprehensionAppendNode): self.value_expr.annotate(code) -class InlinedGeneratorExpressionNode(ExprNode): - # An inlined generator expression for which the result is calculated - # inside of the loop and returned as a single, first and only Generator - # return value. - # This will only be created by transforms when replacing safe builtin - # calls on generator expressions. +class InlinedGeneratorExpressionNode(ExprNode): + # An inlined generator expression for which the result is calculated + # inside of the loop and returned as a single, first and only Generator + # return value. + # This will only be created by transforms when replacing safe builtin + # calls on generator expressions. # - # gen GeneratorExpressionNode the generator, not containing any YieldExprNodes - # orig_func String the name of the builtin function this node replaces - # target ExprNode or None a 'target' for a ComprehensionAppend node - - subexprs = ["gen"] - orig_func = None - target = None - is_temp = True + # gen GeneratorExpressionNode the generator, not containing any YieldExprNodes + # orig_func String the name of the builtin function this node replaces + # target ExprNode or None a 'target' for a ComprehensionAppend node + + subexprs = ["gen"] + orig_func = None + target = None + is_temp = True type = py_object_type - def __init__(self, pos, gen, comprehension_type=None, **kwargs): - gbody = gen.def_node.gbody - gbody.is_inlined = True - if comprehension_type is not None: - assert comprehension_type in (list_type, set_type, dict_type), comprehension_type - gbody.inlined_comprehension_type = comprehension_type - kwargs.update( - target=RawCNameExprNode(pos, comprehension_type, Naming.retval_cname), - type=comprehension_type, - ) - super(InlinedGeneratorExpressionNode, self).__init__(pos, gen=gen, **kwargs) + def __init__(self, pos, gen, comprehension_type=None, **kwargs): + gbody = gen.def_node.gbody + gbody.is_inlined = True + if comprehension_type is not None: + assert comprehension_type in (list_type, set_type, dict_type), comprehension_type + gbody.inlined_comprehension_type = comprehension_type + kwargs.update( + target=RawCNameExprNode(pos, comprehension_type, Naming.retval_cname), + type=comprehension_type, + ) + super(InlinedGeneratorExpressionNode, self).__init__(pos, gen=gen, **kwargs) def may_be_none(self): - return self.orig_func not in ('any', 'all', 'sorted') + return self.orig_func not in ('any', 'all', 'sorted') def infer_type(self, env): - return self.type + return self.type def analyse_types(self, env): - self.gen = self.gen.analyse_expressions(env) + self.gen = self.gen.analyse_expressions(env) return self - def generate_result_code(self, code): - code.putln("%s = __Pyx_Generator_Next(%s); %s" % ( - self.result(), self.gen.result(), - code.error_goto_if_null(self.result(), self.pos))) - code.put_gotref(self.result()) - - -class MergedSequenceNode(ExprNode): - """ - Merge a sequence of iterables into a set/list/tuple. - - The target collection is determined by self.type, which must be set externally. - - args [ExprNode] - """ - subexprs = ['args'] - is_temp = True - gil_message = "Constructing Python collection" - - def __init__(self, pos, args, type): - if type in (list_type, tuple_type) and args and args[0].is_sequence_constructor: - # construct a list directly from the first argument that we can then extend - if args[0].type is not list_type: - args[0] = ListNode(args[0].pos, args=args[0].args, is_temp=True) - ExprNode.__init__(self, pos, args=args, type=type) - - def calculate_constant_result(self): - result = [] - for item in self.args: - if item.is_sequence_constructor and item.mult_factor: - if item.mult_factor.constant_result <= 0: - continue - # otherwise, adding each item once should be enough - if item.is_set_literal or item.is_sequence_constructor: - # process items in order - items = (arg.constant_result for arg in item.args) - else: - items = item.constant_result - result.extend(items) - if self.type is set_type: - result = set(result) - elif self.type is tuple_type: - result = tuple(result) - else: - assert self.type is list_type - self.constant_result = result - - def compile_time_value(self, denv): - result = [] - for item in self.args: - if item.is_sequence_constructor and item.mult_factor: - if item.mult_factor.compile_time_value(denv) <= 0: - continue - if item.is_set_literal or item.is_sequence_constructor: - # process items in order - items = (arg.compile_time_value(denv) for arg in item.args) - else: - items = item.compile_time_value(denv) - result.extend(items) - if self.type is set_type: - try: - result = set(result) - except Exception as e: - self.compile_time_value_error(e) - elif self.type is tuple_type: - result = tuple(result) - else: - assert self.type is list_type - return result - - def type_dependencies(self, env): - return () - - def infer_type(self, env): - return self.type - - def analyse_types(self, env): - args = [ - arg.analyse_types(env).coerce_to_pyobject(env).as_none_safe_node( - # FIXME: CPython's error message starts with the runtime function name - 'argument after * must be an iterable, not NoneType') - for arg in self.args - ] - - if len(args) == 1 and args[0].type is self.type: - # strip this intermediate node and use the bare collection - return args[0] - - assert self.type in (set_type, list_type, tuple_type) - - self.args = args + def generate_result_code(self, code): + code.putln("%s = __Pyx_Generator_Next(%s); %s" % ( + self.result(), self.gen.result(), + code.error_goto_if_null(self.result(), self.pos))) + code.put_gotref(self.result()) + + +class MergedSequenceNode(ExprNode): + """ + Merge a sequence of iterables into a set/list/tuple. + + The target collection is determined by self.type, which must be set externally. + + args [ExprNode] + """ + subexprs = ['args'] + is_temp = True + gil_message = "Constructing Python collection" + + def __init__(self, pos, args, type): + if type in (list_type, tuple_type) and args and args[0].is_sequence_constructor: + # construct a list directly from the first argument that we can then extend + if args[0].type is not list_type: + args[0] = ListNode(args[0].pos, args=args[0].args, is_temp=True) + ExprNode.__init__(self, pos, args=args, type=type) + + def calculate_constant_result(self): + result = [] + for item in self.args: + if item.is_sequence_constructor and item.mult_factor: + if item.mult_factor.constant_result <= 0: + continue + # otherwise, adding each item once should be enough + if item.is_set_literal or item.is_sequence_constructor: + # process items in order + items = (arg.constant_result for arg in item.args) + else: + items = item.constant_result + result.extend(items) + if self.type is set_type: + result = set(result) + elif self.type is tuple_type: + result = tuple(result) + else: + assert self.type is list_type + self.constant_result = result + + def compile_time_value(self, denv): + result = [] + for item in self.args: + if item.is_sequence_constructor and item.mult_factor: + if item.mult_factor.compile_time_value(denv) <= 0: + continue + if item.is_set_literal or item.is_sequence_constructor: + # process items in order + items = (arg.compile_time_value(denv) for arg in item.args) + else: + items = item.compile_time_value(denv) + result.extend(items) + if self.type is set_type: + try: + result = set(result) + except Exception as e: + self.compile_time_value_error(e) + elif self.type is tuple_type: + result = tuple(result) + else: + assert self.type is list_type + return result + + def type_dependencies(self, env): + return () + + def infer_type(self, env): + return self.type + + def analyse_types(self, env): + args = [ + arg.analyse_types(env).coerce_to_pyobject(env).as_none_safe_node( + # FIXME: CPython's error message starts with the runtime function name + 'argument after * must be an iterable, not NoneType') + for arg in self.args + ] + + if len(args) == 1 and args[0].type is self.type: + # strip this intermediate node and use the bare collection + return args[0] + + assert self.type in (set_type, list_type, tuple_type) + + self.args = args return self - def may_be_none(self): - return False - - def generate_evaluation_code(self, code): - code.mark_pos(self.pos) - self.allocate_temp_result(code) - - is_set = self.type is set_type - - args = iter(self.args) - item = next(args) - item.generate_evaluation_code(code) - if (is_set and item.is_set_literal or - not is_set and item.is_sequence_constructor and item.type is list_type): - code.putln("%s = %s;" % (self.result(), item.py_result())) - item.generate_post_assignment_code(code) - else: - code.putln("%s = %s(%s); %s" % ( - self.result(), - 'PySet_New' if is_set else 'PySequence_List', - item.py_result(), - code.error_goto_if_null(self.result(), self.pos))) - code.put_gotref(self.py_result()) - item.generate_disposal_code(code) - item.free_temps(code) - - helpers = set() - if is_set: - add_func = "PySet_Add" - extend_func = "__Pyx_PySet_Update" - else: - add_func = "__Pyx_ListComp_Append" - extend_func = "__Pyx_PyList_Extend" - - for item in args: - if (is_set and (item.is_set_literal or item.is_sequence_constructor) or - (item.is_sequence_constructor and not item.mult_factor)): - if not is_set and item.args: - helpers.add(("ListCompAppend", "Optimize.c")) - for arg in item.args: - arg.generate_evaluation_code(code) - code.put_error_if_neg(arg.pos, "%s(%s, %s)" % ( - add_func, - self.result(), - arg.py_result())) - arg.generate_disposal_code(code) - arg.free_temps(code) - continue - - if is_set: - helpers.add(("PySet_Update", "Builtins.c")) - else: - helpers.add(("ListExtend", "Optimize.c")) - - item.generate_evaluation_code(code) - code.put_error_if_neg(item.pos, "%s(%s, %s)" % ( - extend_func, - self.result(), - item.py_result())) - item.generate_disposal_code(code) - item.free_temps(code) - - if self.type is tuple_type: - code.putln("{") - code.putln("PyObject *%s = PyList_AsTuple(%s);" % ( - Naming.quick_temp_cname, - self.result())) - code.put_decref(self.result(), py_object_type) - code.putln("%s = %s; %s" % ( - self.result(), - Naming.quick_temp_cname, - code.error_goto_if_null(self.result(), self.pos))) - code.put_gotref(self.result()) - code.putln("}") - - for helper in sorted(helpers): - code.globalstate.use_utility_code(UtilityCode.load_cached(*helper)) - - def annotate(self, code): - for item in self.args: - item.annotate(code) - - -class SetNode(ExprNode): - """ - Set constructor. - """ + def may_be_none(self): + return False + + def generate_evaluation_code(self, code): + code.mark_pos(self.pos) + self.allocate_temp_result(code) + + is_set = self.type is set_type + + args = iter(self.args) + item = next(args) + item.generate_evaluation_code(code) + if (is_set and item.is_set_literal or + not is_set and item.is_sequence_constructor and item.type is list_type): + code.putln("%s = %s;" % (self.result(), item.py_result())) + item.generate_post_assignment_code(code) + else: + code.putln("%s = %s(%s); %s" % ( + self.result(), + 'PySet_New' if is_set else 'PySequence_List', + item.py_result(), + code.error_goto_if_null(self.result(), self.pos))) + code.put_gotref(self.py_result()) + item.generate_disposal_code(code) + item.free_temps(code) + + helpers = set() + if is_set: + add_func = "PySet_Add" + extend_func = "__Pyx_PySet_Update" + else: + add_func = "__Pyx_ListComp_Append" + extend_func = "__Pyx_PyList_Extend" + + for item in args: + if (is_set and (item.is_set_literal or item.is_sequence_constructor) or + (item.is_sequence_constructor and not item.mult_factor)): + if not is_set and item.args: + helpers.add(("ListCompAppend", "Optimize.c")) + for arg in item.args: + arg.generate_evaluation_code(code) + code.put_error_if_neg(arg.pos, "%s(%s, %s)" % ( + add_func, + self.result(), + arg.py_result())) + arg.generate_disposal_code(code) + arg.free_temps(code) + continue + + if is_set: + helpers.add(("PySet_Update", "Builtins.c")) + else: + helpers.add(("ListExtend", "Optimize.c")) + + item.generate_evaluation_code(code) + code.put_error_if_neg(item.pos, "%s(%s, %s)" % ( + extend_func, + self.result(), + item.py_result())) + item.generate_disposal_code(code) + item.free_temps(code) + + if self.type is tuple_type: + code.putln("{") + code.putln("PyObject *%s = PyList_AsTuple(%s);" % ( + Naming.quick_temp_cname, + self.result())) + code.put_decref(self.result(), py_object_type) + code.putln("%s = %s; %s" % ( + self.result(), + Naming.quick_temp_cname, + code.error_goto_if_null(self.result(), self.pos))) + code.put_gotref(self.result()) + code.putln("}") + + for helper in sorted(helpers): + code.globalstate.use_utility_code(UtilityCode.load_cached(*helper)) + + def annotate(self, code): + for item in self.args: + item.annotate(code) + + +class SetNode(ExprNode): + """ + Set constructor. + """ subexprs = ['args'] - type = set_type - is_set_literal = True + type = set_type + is_set_literal = True gil_message = "Constructing Python set" def analyse_types(self, env): @@ -8659,7 +8659,7 @@ class SetNode(ExprNode): values = [arg.compile_time_value(denv) for arg in self.args] try: return set(values) - except Exception as e: + except Exception as e: self.compile_time_value_error(e) def generate_evaluation_code(self, code): @@ -8692,7 +8692,7 @@ class DictNode(ExprNode): exclude_null_values = False type = dict_type is_dict_literal = True - reject_duplicates = False + reject_duplicates = False obj_conversion_errors = [] @@ -8710,14 +8710,14 @@ class DictNode(ExprNode): for item in self.key_value_pairs] try: return dict(pairs) - except Exception as e: + except Exception as e: self.compile_time_value_error(e) def type_dependencies(self, env): return () def infer_type(self, env): - # TODO: Infer struct constructors. + # TODO: Infer struct constructors. return dict_type def analyse_types(self, env): @@ -8735,13 +8735,13 @@ class DictNode(ExprNode): def coerce_to(self, dst_type, env): if dst_type.is_pyobject: self.release_errors() - if self.type.is_struct_or_union: - if not dict_type.subtype_of(dst_type): - error(self.pos, "Cannot interpret struct as non-dict type '%s'" % dst_type) - return DictNode(self.pos, key_value_pairs=[ - DictItemNode(item.pos, key=item.key.coerce_to_pyobject(env), - value=item.value.coerce_to_pyobject(env)) - for item in self.key_value_pairs]) + if self.type.is_struct_or_union: + if not dict_type.subtype_of(dst_type): + error(self.pos, "Cannot interpret struct as non-dict type '%s'" % dst_type) + return DictNode(self.pos, key_value_pairs=[ + DictItemNode(item.pos, key=item.key.coerce_to_pyobject(env), + value=item.value.coerce_to_pyobject(env)) + for item in self.key_value_pairs]) if not self.type.subtype_of(dst_type): error(self.pos, "Cannot interpret dict as type '%s'" % dst_type) elif dst_type.is_struct_or_union: @@ -8783,9 +8783,9 @@ class DictNode(ExprNode): # pairs are evaluated and used one at a time. code.mark_pos(self.pos) self.allocate_temp_result(code) - - is_dict = self.type.is_pyobject - if is_dict: + + is_dict = self.type.is_pyobject + if is_dict: self.release_errors() code.putln( "%s = __Pyx_PyDict_NewPresized(%d); %s" % ( @@ -8793,51 +8793,51 @@ class DictNode(ExprNode): len(self.key_value_pairs), code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) - - keys_seen = set() - key_type = None - needs_error_helper = False - + + keys_seen = set() + key_type = None + needs_error_helper = False + for item in self.key_value_pairs: item.generate_evaluation_code(code) - if is_dict: + if is_dict: if self.exclude_null_values: code.putln('if (%s) {' % item.value.py_result()) - key = item.key - if self.reject_duplicates: - if keys_seen is not None: - # avoid runtime 'in' checks for literals that we can do at compile time - if not key.is_string_literal: - keys_seen = None - elif key.value in keys_seen: - # FIXME: this could be a compile time error, at least in Cython code - keys_seen = None - elif key_type is not type(key.value): - if key_type is None: - key_type = type(key.value) - keys_seen.add(key.value) - else: - # different types => may not be able to compare at compile time - keys_seen = None - else: - keys_seen.add(key.value) - - if keys_seen is None: - code.putln('if (unlikely(PyDict_Contains(%s, %s))) {' % ( - self.result(), key.py_result())) - # currently only used in function calls - needs_error_helper = True - code.putln('__Pyx_RaiseDoubleKeywordsError("function", %s); %s' % ( - key.py_result(), - code.error_goto(item.pos))) - code.putln("} else {") - - code.put_error_if_neg(self.pos, "PyDict_SetItem(%s, %s, %s)" % ( - self.result(), - item.key.py_result(), - item.value.py_result())) - if self.reject_duplicates and keys_seen is None: - code.putln('}') + key = item.key + if self.reject_duplicates: + if keys_seen is not None: + # avoid runtime 'in' checks for literals that we can do at compile time + if not key.is_string_literal: + keys_seen = None + elif key.value in keys_seen: + # FIXME: this could be a compile time error, at least in Cython code + keys_seen = None + elif key_type is not type(key.value): + if key_type is None: + key_type = type(key.value) + keys_seen.add(key.value) + else: + # different types => may not be able to compare at compile time + keys_seen = None + else: + keys_seen.add(key.value) + + if keys_seen is None: + code.putln('if (unlikely(PyDict_Contains(%s, %s))) {' % ( + self.result(), key.py_result())) + # currently only used in function calls + needs_error_helper = True + code.putln('__Pyx_RaiseDoubleKeywordsError("function", %s); %s' % ( + key.py_result(), + code.error_goto(item.pos))) + code.putln("} else {") + + code.put_error_if_neg(self.pos, "PyDict_SetItem(%s, %s, %s)" % ( + self.result(), + item.key.py_result(), + item.value.py_result())) + if self.reject_duplicates and keys_seen is None: + code.putln('}') if self.exclude_null_values: code.putln('}') else: @@ -8848,15 +8848,15 @@ class DictNode(ExprNode): item.generate_disposal_code(code) item.free_temps(code) - if needs_error_helper: - code.globalstate.use_utility_code( - UtilityCode.load_cached("RaiseDoubleKeywords", "FunctionArguments.c")) - + if needs_error_helper: + code.globalstate.use_utility_code( + UtilityCode.load_cached("RaiseDoubleKeywords", "FunctionArguments.c")) + def annotate(self, code): for item in self.key_value_pairs: item.annotate(code) - + class DictItemNode(ExprNode): # Represents a single item in a DictNode # @@ -9239,16 +9239,16 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin): default_args = [] default_kwargs = [] annotations = [] - - # For global cpdef functions and def/cpdef methods in cdef classes, we must use global constants - # for default arguments to avoid the dependency on the CyFunction object as 'self' argument - # in the underlying C function. Basically, cpdef functions/methods are static C functions, - # so their optional arguments must be static, too. - # TODO: change CyFunction implementation to pass both function object and owning object for method calls - must_use_constants = env.is_c_class_scope or (self.def_node.is_wrapper and env.is_module_scope) - + + # For global cpdef functions and def/cpdef methods in cdef classes, we must use global constants + # for default arguments to avoid the dependency on the CyFunction object as 'self' argument + # in the underlying C function. Basically, cpdef functions/methods are static C functions, + # so their optional arguments must be static, too. + # TODO: change CyFunction implementation to pass both function object and owning object for method calls + must_use_constants = env.is_c_class_scope or (self.def_node.is_wrapper and env.is_module_scope) + for arg in self.def_node.args: - if arg.default and not must_use_constants: + if arg.default and not must_use_constants: if not arg.default.is_literal: arg.is_dynamic = True if arg.type.is_pyobject: @@ -9264,12 +9264,12 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin): if arg.annotation: arg.annotation = self.analyse_annotation(env, arg.annotation) annotations.append((arg.pos, arg.name, arg.annotation)) - - for arg in (self.def_node.star_arg, self.def_node.starstar_arg): - if arg and arg.annotation: + + for arg in (self.def_node.star_arg, self.def_node.starstar_arg): + if arg and arg.annotation: arg.annotation = self.analyse_annotation(env, arg.annotation) - annotations.append((arg.pos, arg.name, arg.annotation)) - + annotations.append((arg.pos, arg.name, arg.annotation)) + annotation = self.def_node.return_type_annotation if annotation: annotation = self.analyse_annotation(env, annotation) @@ -9305,7 +9305,7 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin): if default_args: defaults_tuple = TupleNode(self.pos, args=[ arg.default for arg in default_args]) - self.defaults_tuple = defaults_tuple.analyse_types(env).coerce_to_pyobject(env) + self.defaults_tuple = defaults_tuple.analyse_types(env).coerce_to_pyobject(env) if default_kwargs: defaults_kwdict = DictNode(self.pos, key_value_pairs=[ DictItemNode( @@ -9334,10 +9334,10 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin): self.pos, args=[defaults_tuple, defaults_kwdict])), decorators=None, name=StringEncoding.EncodedString("__defaults__")) - # defaults getter must never live in class scopes, it's always a module function - module_scope = env.global_scope() - defaults_getter.analyse_declarations(module_scope) - defaults_getter = defaults_getter.analyse_expressions(module_scope) + # defaults getter must never live in class scopes, it's always a module function + module_scope = env.global_scope() + defaults_getter.analyse_declarations(module_scope) + defaults_getter = defaults_getter.analyse_expressions(module_scope) defaults_getter.body = defaults_getter.body.analyse_expressions( defaults_getter.local_scope) defaults_getter.py_wrapper_required = False @@ -9421,7 +9421,7 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin): elif def_node.is_classmethod: flags.append('__Pyx_CYFUNCTION_CLASSMETHOD') - if def_node.local_scope.parent_scope.is_c_class_scope and not def_node.entry.is_anonymous: + if def_node.local_scope.parent_scope.is_c_class_scope and not def_node.entry.is_anonymous: flags.append('__Pyx_CYFUNCTION_CCLASS') if flags: @@ -9471,8 +9471,8 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin): if self.defaults_kwdict: code.putln('__Pyx_CyFunction_SetDefaultsKwDict(%s, %s);' % ( self.result(), self.defaults_kwdict.py_result())) - if def_node.defaults_getter and not self.specialized_cpdefs: - # Fused functions do not support dynamic defaults, only their specialisations can have them for now. + if def_node.defaults_getter and not self.specialized_cpdefs: + # Fused functions do not support dynamic defaults, only their specialisations can have them for now. code.putln('__Pyx_CyFunction_SetDefaultsGetter(%s, %s);' % ( self.result(), def_node.defaults_getter.entry.pyfunc_cname)) if self.annotations_dict: @@ -9501,7 +9501,7 @@ class CodeObjectNode(ExprNode): subexprs = ['varnames'] is_temp = False - result_code = None + result_code = None def __init__(self, def_node): ExprNode.__init__(self, def_node.pos, def_node=def_node) @@ -9518,24 +9518,24 @@ class CodeObjectNode(ExprNode): def may_be_none(self): return False - def calculate_result_code(self, code=None): - if self.result_code is None: - self.result_code = code.get_py_const(py_object_type, 'codeobj', cleanup_level=2) + def calculate_result_code(self, code=None): + if self.result_code is None: + self.result_code = code.get_py_const(py_object_type, 'codeobj', cleanup_level=2) return self.result_code def generate_result_code(self, code): - if self.result_code is None: - self.result_code = code.get_py_const(py_object_type, 'codeobj', cleanup_level=2) + if self.result_code is None: + self.result_code = code.get_py_const(py_object_type, 'codeobj', cleanup_level=2) - code = code.get_cached_constants_writer(self.result_code) - if code is None: - return # already initialised + code = code.get_cached_constants_writer(self.result_code) + if code is None: + return # already initialised code.mark_pos(self.pos) func = self.def_node func_name = code.get_py_string_const( func.name, identifier=True, is_str=False, unicode_value=func.name) # FIXME: better way to get the module file path at module init time? Encoding to use? - file_path = StringEncoding.bytes_literal(func.pos[0].get_filenametable_entry().encode('utf8'), 'utf8') + file_path = StringEncoding.bytes_literal(func.pos[0].get_filenametable_entry().encode('utf8'), 'utf8') # XXX Use get_description() to set arcadia root relative filename file_path = StringEncoding.bytes_literal(func.pos[0].get_description().encode('utf8'), 'utf8') file_path_const = code.get_py_string_const(file_path, identifier=False, is_str=True) @@ -9635,10 +9635,10 @@ class DefaultsTupleNode(TupleNode): args.append(arg) super(DefaultsTupleNode, self).__init__(pos, args=args) - def analyse_types(self, env, skip_children=False): - return super(DefaultsTupleNode, self).analyse_types(env, skip_children).coerce_to_pyobject(env) + def analyse_types(self, env, skip_children=False): + return super(DefaultsTupleNode, self).analyse_types(env, skip_children).coerce_to_pyobject(env) + - class DefaultsKwDictNode(DictNode): # CyFunction's __kwdefaults__ dict @@ -9669,7 +9669,7 @@ class LambdaNode(InnerFunctionNode): name = StringEncoding.EncodedString('<lambda>') def analyse_declarations(self, env): - self.lambda_name = self.def_node.lambda_name = env.next_id('lambda') + self.lambda_name = self.def_node.lambda_name = env.next_id('lambda') self.def_node.no_assignment_synthesis = True self.def_node.pymethdef_required = True self.def_node.analyse_declarations(env) @@ -9698,7 +9698,7 @@ class GeneratorExpressionNode(LambdaNode): binding = False def analyse_declarations(self, env): - self.genexpr_name = env.next_id('genexpr') + self.genexpr_name = env.next_id('genexpr') super(GeneratorExpressionNode, self).analyse_declarations(env) # No pymethdef required self.def_node.pymethdef_required = False @@ -9728,13 +9728,13 @@ class YieldExprNode(ExprNode): type = py_object_type label_num = 0 is_yield_from = False - is_await = False + is_await = False in_async_gen = False - expr_keyword = 'yield' + expr_keyword = 'yield' def analyse_types(self, env): if not self.label_num or (self.is_yield_from and self.in_async_gen): - error(self.pos, "'%s' not supported here" % self.expr_keyword) + error(self.pos, "'%s' not supported here" % self.expr_keyword) self.is_temp = 1 if self.arg is not None: self.arg = self.arg.analyse_types(env) @@ -9820,22 +9820,22 @@ class YieldExprNode(ExprNode): class _YieldDelegationExprNode(YieldExprNode): - def yield_from_func(self, code): + def yield_from_func(self, code): raise NotImplementedError() - def generate_evaluation_code(self, code, source_cname=None, decref_source=False): - if source_cname is None: - self.arg.generate_evaluation_code(code) - code.putln("%s = %s(%s, %s);" % ( + def generate_evaluation_code(self, code, source_cname=None, decref_source=False): + if source_cname is None: + self.arg.generate_evaluation_code(code) + code.putln("%s = %s(%s, %s);" % ( Naming.retval_cname, - self.yield_from_func(code), + self.yield_from_func(code), Naming.generator_cname, - self.arg.py_result() if source_cname is None else source_cname)) - if source_cname is None: - self.arg.generate_disposal_code(code) - self.arg.free_temps(code) - elif decref_source: - code.put_decref_clear(source_cname, py_object_type) + self.arg.py_result() if source_cname is None else source_cname)) + if source_cname is None: + self.arg.generate_disposal_code(code) + self.arg.free_temps(code) + elif decref_source: + code.put_decref_clear(source_cname, py_object_type) code.put_xgotref(Naming.retval_cname) code.putln("if (likely(%s)) {" % Naming.retval_cname) @@ -9843,26 +9843,26 @@ class _YieldDelegationExprNode(YieldExprNode): code.putln("} else {") # either error or sub-generator has normally terminated: return value => node result if self.result_is_used: - self.fetch_iteration_result(code) + self.fetch_iteration_result(code) else: - self.handle_iteration_exception(code) + self.handle_iteration_exception(code) code.putln("}") - def fetch_iteration_result(self, code): - # YieldExprNode has allocated the result temp for us - code.putln("%s = NULL;" % self.result()) - code.put_error_if_neg(self.pos, "__Pyx_PyGen_FetchStopIterationValue(&%s)" % self.result()) - code.put_gotref(self.result()) - - def handle_iteration_exception(self, code): + def fetch_iteration_result(self, code): + # YieldExprNode has allocated the result temp for us + code.putln("%s = NULL;" % self.result()) + code.put_error_if_neg(self.pos, "__Pyx_PyGen_FetchStopIterationValue(&%s)" % self.result()) + code.put_gotref(self.result()) + + def handle_iteration_exception(self, code): code.putln("PyObject* exc_type = __Pyx_PyErr_Occurred();") - code.putln("if (exc_type) {") + code.putln("if (exc_type) {") code.putln("if (likely(exc_type == PyExc_StopIteration || (exc_type != PyExc_GeneratorExit &&" " __Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration)))) PyErr_Clear();") - code.putln("else %s" % code.error_goto(self.pos)) - code.putln("}") - - + code.putln("else %s" % code.error_goto(self.pos)) + code.putln("}") + + class YieldFromExprNode(_YieldDelegationExprNode): # "yield from GEN" expression is_yield_from = True @@ -9880,44 +9880,44 @@ class YieldFromExprNode(_YieldDelegationExprNode): class AwaitExprNode(_YieldDelegationExprNode): - # 'await' expression node - # - # arg ExprNode the Awaitable value to await - # label_num integer yield label number - - is_await = True - expr_keyword = 'await' - - def coerce_yield_argument(self, env): - if self.arg is not None: - # FIXME: use same check as in YieldFromExprNode.coerce_yield_argument() ? - self.arg = self.arg.coerce_to_pyobject(env) - - def yield_from_func(self, code): - code.globalstate.use_utility_code(UtilityCode.load_cached("CoroutineYieldFrom", "Coroutine.c")) - return "__Pyx_Coroutine_Yield_From" - - -class AwaitIterNextExprNode(AwaitExprNode): - # 'await' expression node as part of 'async for' iteration - # - # Breaks out of loop on StopAsyncIteration exception. - + # 'await' expression node + # + # arg ExprNode the Awaitable value to await + # label_num integer yield label number + + is_await = True + expr_keyword = 'await' + + def coerce_yield_argument(self, env): + if self.arg is not None: + # FIXME: use same check as in YieldFromExprNode.coerce_yield_argument() ? + self.arg = self.arg.coerce_to_pyobject(env) + + def yield_from_func(self, code): + code.globalstate.use_utility_code(UtilityCode.load_cached("CoroutineYieldFrom", "Coroutine.c")) + return "__Pyx_Coroutine_Yield_From" + + +class AwaitIterNextExprNode(AwaitExprNode): + # 'await' expression node as part of 'async for' iteration + # + # Breaks out of loop on StopAsyncIteration exception. + def _generate_break(self, code): - code.globalstate.use_utility_code(UtilityCode.load_cached("StopAsyncIteration", "Coroutine.c")) + code.globalstate.use_utility_code(UtilityCode.load_cached("StopAsyncIteration", "Coroutine.c")) code.putln("PyObject* exc_type = __Pyx_PyErr_Occurred();") code.putln("if (unlikely(exc_type && (exc_type == __Pyx_PyExc_StopAsyncIteration || (" " exc_type != PyExc_StopIteration && exc_type != PyExc_GeneratorExit &&" " __Pyx_PyErr_GivenExceptionMatches(exc_type, __Pyx_PyExc_StopAsyncIteration))))) {") - code.putln("PyErr_Clear();") - code.putln("break;") - code.putln("}") + code.putln("PyErr_Clear();") + code.putln("break;") + code.putln("}") def fetch_iteration_result(self, code): assert code.break_label, "AwaitIterNextExprNode outside of 'async for' loop" self._generate_break(code) - super(AwaitIterNextExprNode, self).fetch_iteration_result(code) - + super(AwaitIterNextExprNode, self).fetch_iteration_result(code) + def generate_sent_value_handling_code(self, code, value_cname): assert code.break_label, "AwaitIterNextExprNode outside of 'async for' loop" code.putln("if (unlikely(!%s)) {" % value_cname) @@ -9925,7 +9925,7 @@ class AwaitIterNextExprNode(AwaitExprNode): # all non-break exceptions are errors, as in parent class code.putln(code.error_goto(self.pos)) code.putln("}") - + class GlobalsExprNode(AtomicExprNode): type = dict_type @@ -10046,7 +10046,7 @@ class UnopNode(ExprNode): operand = self.operand.compile_time_value(denv) try: return func(operand) - except Exception as e: + except Exception as e: self.compile_time_value_error(e) def infer_type(self, env): @@ -10088,7 +10088,7 @@ class UnopNode(ExprNode): return self.operand.check_const() def is_py_operation(self): - return self.operand.type.is_pyobject or self.operand.type.is_ctuple + return self.operand.type.is_pyobject or self.operand.type.is_ctuple def is_pythran_operation(self, env): np_pythran = has_np_pythran(env) @@ -10117,14 +10117,14 @@ class UnopNode(ExprNode): self.operand.pythran_result())) elif self.operand.type.is_pyobject: self.generate_py_operation_code(code) - elif self.is_temp: - if self.is_cpp_operation() and self.exception_check == '+': - translate_cpp_exception(code, self.pos, - "%s = %s %s;" % (self.result(), self.operator, self.operand.result()), - self.result() if self.type.is_pyobject else None, - self.exception_value, self.in_nogil_context) - else: - code.putln("%s = %s %s;" % (self.result(), self.operator, self.operand.result())) + elif self.is_temp: + if self.is_cpp_operation() and self.exception_check == '+': + translate_cpp_exception(code, self.pos, + "%s = %s %s;" % (self.result(), self.operator, self.operand.result()), + self.result() if self.type.is_pyobject else None, + self.exception_value, self.in_nogil_context) + else: + code.putln("%s = %s %s;" % (self.result(), self.operator, self.operand.result())) def generate_py_operation_code(self, code): function = self.py_operation_function(code) @@ -10142,23 +10142,23 @@ class UnopNode(ExprNode): (self.operator, self.operand.type)) self.type = PyrexTypes.error_type - def analyse_cpp_operation(self, env, overload_check=True): - entry = env.lookup_operator(self.operator, [self.operand]) - if overload_check and not entry: - self.type_error() - return - if entry: - self.exception_check = entry.type.exception_check - self.exception_value = entry.type.exception_value - if self.exception_check == '+': - self.is_temp = True - if self.exception_value is None: - env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp")) - else: - self.exception_check = '' - self.exception_value = '' + def analyse_cpp_operation(self, env, overload_check=True): + entry = env.lookup_operator(self.operator, [self.operand]) + if overload_check and not entry: + self.type_error() + return + if entry: + self.exception_check = entry.type.exception_check + self.exception_value = entry.type.exception_value + if self.exception_check == '+': + self.is_temp = True + if self.exception_value is None: + env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp")) + else: + self.exception_check = '' + self.exception_value = '' cpp_type = self.operand.type.find_cpp_operation_type(self.operator) - if overload_check and cpp_type is None: + if overload_check and cpp_type is None: error(self.pos, "'%s' operator not defined for %s" % ( self.operator, type)) self.type_error() @@ -10181,7 +10181,7 @@ class NotNode(UnopNode): operand = self.operand.compile_time_value(denv) try: return not operand - except Exception as e: + except Exception as e: self.compile_time_value_error(e) def infer_unop_type(self, env, operand_type): @@ -10191,7 +10191,7 @@ class NotNode(UnopNode): self.operand = self.operand.analyse_types(env) operand_type = self.operand.type if operand_type.is_cpp_class: - self.analyse_cpp_operation(env) + self.analyse_cpp_operation(env) else: self.operand = self.operand.coerce_to_boolean(env) return self @@ -10329,12 +10329,12 @@ class AmpersandNode(CUnopNode): self.operand = self.operand.analyse_types(env) argtype = self.operand.type if argtype.is_cpp_class: - self.analyse_cpp_operation(env, overload_check=False) + self.analyse_cpp_operation(env, overload_check=False) if not (argtype.is_cfunction or argtype.is_reference or self.operand.is_addressable()): if argtype.is_memoryviewslice: self.error("Cannot take address of memoryview slice") else: - self.error("Taking address of non-lvalue (type %s)" % argtype) + self.error("Taking address of non-lvalue (type %s)" % argtype) return self if argtype.is_pyobject: self.error("Cannot take address of Python %s" % ( @@ -10342,8 +10342,8 @@ class AmpersandNode(CUnopNode): "object attribute '%s'" % self.operand.attribute if self.operand.is_attribute else "object")) return self - if not argtype.is_cpp_class or not self.type: - self.type = PyrexTypes.c_ptr_type(argtype) + if not argtype.is_cpp_class or not self.type: + self.type = PyrexTypes.c_ptr_type(argtype) return self def check_const(self): @@ -10358,11 +10358,11 @@ class AmpersandNode(CUnopNode): return "(&%s)" % self.operand.result() def generate_result_code(self, code): - if (self.operand.type.is_cpp_class and self.exception_check == '+'): - translate_cpp_exception(code, self.pos, - "%s = %s %s;" % (self.result(), self.operator, self.operand.result()), - self.result() if self.type.is_pyobject else None, - self.exception_value, self.in_nogil_context) + if (self.operand.type.is_cpp_class and self.exception_check == '+'): + translate_cpp_exception(code, self.pos, + "%s = %s %s;" % (self.result(), self.operator, self.operand.result()), + self.result() if self.type.is_pyobject else None, + self.exception_value, self.in_nogil_context) unop_node_classes = { @@ -10432,15 +10432,15 @@ class TypecastNode(ExprNode): return CoerceIntToBytesNode(self.operand, env) elif self.operand.type.can_coerce_to_pyobject(env): self.result_ctype = py_object_type - self.operand = self.operand.coerce_to(self.type, env) + self.operand = self.operand.coerce_to(self.type, env) else: if self.operand.type.is_ptr: if not (self.operand.type.base_type.is_void or self.operand.type.base_type.is_struct): error(self.pos, "Python objects cannot be cast from pointers of primitive types") else: # Should this be an error? - warning(self.pos, "No conversion from %s to %s, python object pointer used." % ( - self.operand.type, self.type)) + warning(self.pos, "No conversion from %s to %s, python object pointer used." % ( + self.operand.type, self.type)) self.operand = self.operand.coerce_to_simple(env) elif from_py and not to_py: if self.type.create_from_py_utility_code(env): @@ -10449,8 +10449,8 @@ class TypecastNode(ExprNode): if not (self.type.base_type.is_void or self.type.base_type.is_struct): error(self.pos, "Python objects cannot be cast to pointers of primitive types") else: - warning(self.pos, "No conversion from %s to %s, python object pointer used." % ( - self.type, self.operand.type)) + warning(self.pos, "No conversion from %s to %s, python object pointer used." % ( + self.type, self.operand.type)) elif from_py and to_py: if self.typecheck: self.operand = PyTypeTestNode(self.operand, self.type, env, notnone=True) @@ -10462,13 +10462,13 @@ class TypecastNode(ExprNode): elif self.operand.type.is_fused: self.operand = self.operand.coerce_to(self.type, env) #self.type = self.operand.type - if self.type.is_ptr and self.type.base_type.is_cfunction and self.type.base_type.nogil: - op_type = self.operand.type - if op_type.is_ptr: - op_type = op_type.base_type - if op_type.is_cfunction and not op_type.nogil: - warning(self.pos, - "Casting a GIL-requiring function into a nogil function circumvents GIL validation", 1) + if self.type.is_ptr and self.type.base_type.is_cfunction and self.type.base_type.nogil: + op_type = self.operand.type + if op_type.is_ptr: + op_type = op_type.base_type + if op_type.is_cfunction and not op_type.nogil: + warning(self.pos, + "Casting a GIL-requiring function into a nogil function circumvents GIL validation", 1) return self def is_simple(self): @@ -10538,7 +10538,7 @@ ERR_STEPS = ("Strides may only be given to indicate contiguity. " ERR_NOT_POINTER = "Can only create cython.array from pointer or array" ERR_BASE_TYPE = "Pointer base type does not match cython.array base type" - + class CythonArrayNode(ExprNode): """ Used when a pointer of base_type is cast to a memoryviewslice with that @@ -10667,7 +10667,7 @@ class CythonArrayNode(ExprNode): axes[-1] = ('direct', 'contig') self.coercion_type = PyrexTypes.MemoryViewSliceType(array_dtype, axes) - self.coercion_type.validate_memslice_dtype(self.pos) + self.coercion_type.validate_memslice_dtype(self.pos) self.type = self.get_cython_array_type(env) MemoryView.use_cython_array_utility_code(env) env.use_utility_code(MemoryView.typeinfo_to_format_code) @@ -10697,7 +10697,7 @@ class CythonArrayNode(ExprNode): shapes_temp = code.funcstate.allocate_temp(py_object_type, True) format_temp = code.funcstate.allocate_temp(py_object_type, True) - itemsize = "sizeof(%s)" % dtype.empty_declaration_code() + itemsize = "sizeof(%s)" % dtype.empty_declaration_code() type_info = Buffer.get_type_information_cname(code, dtype) if self.operand.type.is_ptr: @@ -10805,8 +10805,8 @@ class SizeofTypeNode(SizeofNode): def check_type(self): arg_type = self.arg_type - if not arg_type: - return + if not arg_type: + return if arg_type.is_pyobject and not arg_type.is_extension_type: error(self.pos, "Cannot take sizeof Python object") elif arg_type.is_void: @@ -10820,7 +10820,7 @@ class SizeofTypeNode(SizeofNode): # we want the size of the actual struct arg_code = self.arg_type.declaration_code("", deref=1) else: - arg_code = self.arg_type.empty_declaration_code() + arg_code = self.arg_type.empty_declaration_code() return "(sizeof(%s))" % arg_code @@ -10851,78 +10851,78 @@ class SizeofVarNode(SizeofNode): def generate_result_code(self, code): pass - -class TypeidNode(ExprNode): - # C++ typeid operator applied to a type or variable - # - # operand ExprNode - # arg_type ExprNode - # is_variable boolean - - type = PyrexTypes.error_type - - subexprs = ['operand'] - - arg_type = None - is_variable = None - is_temp = 1 - - def get_type_info_type(self, env): - env_module = env - while not env_module.is_module_scope: - env_module = env_module.outer_scope - typeinfo_module = env_module.find_module('libcpp.typeinfo', self.pos) - typeinfo_entry = typeinfo_module.lookup('type_info') - return PyrexTypes.CFakeReferenceType(PyrexTypes.c_const_type(typeinfo_entry.type)) - + +class TypeidNode(ExprNode): + # C++ typeid operator applied to a type or variable + # + # operand ExprNode + # arg_type ExprNode + # is_variable boolean + + type = PyrexTypes.error_type + + subexprs = ['operand'] + + arg_type = None + is_variable = None + is_temp = 1 + + def get_type_info_type(self, env): + env_module = env + while not env_module.is_module_scope: + env_module = env_module.outer_scope + typeinfo_module = env_module.find_module('libcpp.typeinfo', self.pos) + typeinfo_entry = typeinfo_module.lookup('type_info') + return PyrexTypes.CFakeReferenceType(PyrexTypes.c_const_type(typeinfo_entry.type)) + cpp_message = 'typeid operator' - def analyse_types(self, env): + def analyse_types(self, env): self.cpp_check(env) - type_info = self.get_type_info_type(env) - if not type_info: - self.error("The 'libcpp.typeinfo' module must be cimported to use the typeid() operator") - return self - self.type = type_info - as_type = self.operand.analyse_as_type(env) - if as_type: - self.arg_type = as_type - self.is_type = True - else: - self.arg_type = self.operand.analyse_types(env) - self.is_type = False - if self.arg_type.type.is_pyobject: - self.error("Cannot use typeid on a Python object") - return self - elif self.arg_type.type.is_void: - self.error("Cannot use typeid on void") - return self - elif not self.arg_type.type.is_complete(): - self.error("Cannot use typeid on incomplete type '%s'" % self.arg_type.type) - return self - env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp")) - return self - - def error(self, mess): - error(self.pos, mess) - self.type = PyrexTypes.error_type - self.result_code = "<error>" - - def check_const(self): - return True - - def calculate_result_code(self): - return self.temp_code - - def generate_result_code(self, code): - if self.is_type: - arg_code = self.arg_type.empty_declaration_code() - else: - arg_code = self.arg_type.result() - translate_cpp_exception(code, self.pos, - "%s = typeid(%s);" % (self.temp_code, arg_code), - None, None, self.in_nogil_context) - + type_info = self.get_type_info_type(env) + if not type_info: + self.error("The 'libcpp.typeinfo' module must be cimported to use the typeid() operator") + return self + self.type = type_info + as_type = self.operand.analyse_as_type(env) + if as_type: + self.arg_type = as_type + self.is_type = True + else: + self.arg_type = self.operand.analyse_types(env) + self.is_type = False + if self.arg_type.type.is_pyobject: + self.error("Cannot use typeid on a Python object") + return self + elif self.arg_type.type.is_void: + self.error("Cannot use typeid on void") + return self + elif not self.arg_type.type.is_complete(): + self.error("Cannot use typeid on incomplete type '%s'" % self.arg_type.type) + return self + env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp")) + return self + + def error(self, mess): + error(self.pos, mess) + self.type = PyrexTypes.error_type + self.result_code = "<error>" + + def check_const(self): + return True + + def calculate_result_code(self): + return self.temp_code + + def generate_result_code(self, code): + if self.is_type: + arg_code = self.arg_type.empty_declaration_code() + else: + arg_code = self.arg_type.result() + translate_cpp_exception(code, self.pos, + "%s = typeid(%s);" % (self.temp_code, arg_code), + None, None, self.in_nogil_context) + class TypeofNode(ExprNode): # Compile-time type of an expression, as a string. # @@ -11034,7 +11034,7 @@ class BinopNode(ExprNode): operand2 = self.operand2.compile_time_value(denv) try: return func(operand1, operand2) - except Exception as e: + except Exception as e: self.compile_time_value_error(e) def infer_type(self, env): @@ -11068,7 +11068,7 @@ class BinopNode(ExprNode): return self.is_py_operation_types(self.operand1.type, self.operand2.type) def is_py_operation_types(self, type1, type2): - return type1.is_pyobject or type2.is_pyobject or type1.is_ctuple or type2.is_ctuple + return type1.is_pyobject or type2.is_pyobject or type1.is_ctuple or type2.is_ctuple def is_pythran_operation(self, env): return self.is_pythran_operation_types(self.operand1.type, self.operand2.type, env) @@ -11089,14 +11089,14 @@ class BinopNode(ExprNode): self.type_error() return func_type = entry.type - self.exception_check = func_type.exception_check - self.exception_value = func_type.exception_value - if self.exception_check == '+': - # Used by NumBinopNodes to break up expressions involving multiple - # operators so that exceptions can be handled properly. - self.is_temp = 1 - if self.exception_value is None: - env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp")) + self.exception_check = func_type.exception_check + self.exception_value = func_type.exception_value + if self.exception_check == '+': + # Used by NumBinopNodes to break up expressions involving multiple + # operators so that exceptions can be handled properly. + self.is_temp = 1 + if self.exception_value is None: + env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp")) if func_type.is_ptr: func_type = func_type.base_type if len(func_type.args) == 1: @@ -11153,19 +11153,19 @@ class BinopNode(ExprNode): if self.type.is_pythran_expr: code.putln("// Pythran binop") code.putln("__Pyx_call_destructor(%s);" % self.result()) - if self.operator == '**': - code.putln("new (&%s) decltype(%s){pythonic::numpy::functor::power{}(%s, %s)};" % ( - self.result(), - self.result(), - self.operand1.pythran_result(), - self.operand2.pythran_result())) - else: - code.putln("new (&%s) decltype(%s){%s %s %s};" % ( - self.result(), - self.result(), - self.operand1.pythran_result(), - self.operator, - self.operand2.pythran_result())) + if self.operator == '**': + code.putln("new (&%s) decltype(%s){pythonic::numpy::functor::power{}(%s, %s)};" % ( + self.result(), + self.result(), + self.operand1.pythran_result(), + self.operand2.pythran_result())) + else: + code.putln("new (&%s) decltype(%s){%s %s %s};" % ( + self.result(), + self.result(), + self.operand1.pythran_result(), + self.operator, + self.operand2.pythran_result())) elif self.operand1.type.is_pyobject: function = self.py_operation_function(code) if self.operator == '**': @@ -11182,15 +11182,15 @@ class BinopNode(ExprNode): code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) elif self.is_temp: - # C++ overloaded operators with exception values are currently all - # handled through temporaries. - if self.is_cpp_operation() and self.exception_check == '+': - translate_cpp_exception(code, self.pos, - "%s = %s;" % (self.result(), self.calculate_result_code()), - self.result() if self.type.is_pyobject else None, - self.exception_value, self.in_nogil_context) - else: - code.putln("%s = %s;" % (self.result(), self.calculate_result_code())) + # C++ overloaded operators with exception values are currently all + # handled through temporaries. + if self.is_cpp_operation() and self.exception_check == '+': + translate_cpp_exception(code, self.pos, + "%s = %s;" % (self.result(), self.calculate_result_code()), + self.result() if self.type.is_pyobject else None, + self.exception_value, self.in_nogil_context) + else: + code.putln("%s = %s;" % (self.result(), self.calculate_result_code())) def type_error(self): if not (self.operand1.type.is_error @@ -11222,8 +11222,8 @@ class CBinopNode(BinopNode): cpp_type = None if type1.is_cpp_class or type1.is_ptr: cpp_type = type1.find_cpp_operation_type(self.operator, type2) - if cpp_type is None and (type2.is_cpp_class or type2.is_ptr): - cpp_type = type2.find_cpp_operation_type(self.operator, type1) + if cpp_type is None and (type2.is_cpp_class or type2.is_ptr): + cpp_type = type2.find_cpp_operation_type(self.operator, type1) # FIXME: do we need to handle other cases here? return cpp_type @@ -11327,7 +11327,7 @@ class NumBinopNode(BinopNode): self.operand1.result(), self.operand2.result(), self.overflow_bit_node.overflow_bit) - elif self.type.is_cpp_class or self.infix: + elif self.type.is_cpp_class or self.infix: if is_pythran_expr(self.type): result1, result2 = self.operand1.pythran_result(), self.operand2.pythran_result() else: @@ -11416,14 +11416,14 @@ class AddNode(NumBinopNode): def py_operation_function(self, code): type1, type2 = self.operand1.type, self.operand2.type - + if type1 is unicode_type or type2 is unicode_type: if type1 in (unicode_type, str_type) and type2 in (unicode_type, str_type): is_unicode_concat = True elif isinstance(self.operand1, FormattedValueNode) or isinstance(self.operand2, FormattedValueNode): # Assume that even if we don't know the second type, it's going to be a string. is_unicode_concat = True - else: + else: # Operation depends on the second type. is_unicode_concat = False @@ -11500,7 +11500,7 @@ class DivNode(NumBinopNode): func = compile_time_binary_operators[self.operator] if self.operator == '/' and self.truedivision is None: # => true div for floats, floor div for integers - if isinstance(op1, _py_int_types) and isinstance(op2, _py_int_types): + if isinstance(op1, _py_int_types) and isinstance(op2, _py_int_types): func = compile_time_binary_operators['//'] return func @@ -11519,23 +11519,23 @@ class DivNode(NumBinopNode): func = self.find_compile_time_binary_operator( operand1, operand2) return func(operand1, operand2) - except Exception as e: + except Exception as e: self.compile_time_value_error(e) - def _check_truedivision(self, env): + def _check_truedivision(self, env): if self.cdivision or env.directives['cdivision']: self.ctruedivision = False else: self.ctruedivision = self.truedivision - - def infer_type(self, env): - self._check_truedivision(env) - return self.result_type( - self.operand1.infer_type(env), + + def infer_type(self, env): + self._check_truedivision(env) + return self.result_type( + self.operand1.infer_type(env), self.operand2.infer_type(env), env) - - def analyse_operation(self, env): - self._check_truedivision(env) + + def analyse_operation(self, env): + self._check_truedivision(env) NumBinopNode.analyse_operation(self, env) if self.is_cpp_operation(): self.cdivision = True @@ -11550,7 +11550,7 @@ class DivNode(NumBinopNode): self.operand2 = self.operand2.coerce_to_simple(env) def compute_c_result_type(self, type1, type2): - if self.operator == '/' and self.ctruedivision and not type1.is_cpp_class and not type2.is_cpp_class: + if self.operator == '/' and self.ctruedivision and not type1.is_cpp_class and not type2.is_cpp_class: if not type1.is_float and not type2.is_float: widest_type = PyrexTypes.widest_numeric_type(type1, PyrexTypes.c_double_type) widest_type = PyrexTypes.widest_numeric_type(type2, widest_type) @@ -11566,19 +11566,19 @@ class DivNode(NumBinopNode): def generate_evaluation_code(self, code): if not self.type.is_pyobject and not self.type.is_complex: if self.cdivision is None: - self.cdivision = ( - code.globalstate.directives['cdivision'] - or self.type.is_float - or ((self.type.is_numeric or self.type.is_enum) and not self.type.signed) - ) + self.cdivision = ( + code.globalstate.directives['cdivision'] + or self.type.is_float + or ((self.type.is_numeric or self.type.is_enum) and not self.type.signed) + ) if not self.cdivision: - code.globalstate.use_utility_code( - UtilityCode.load_cached("DivInt", "CMath.c").specialize(self.type)) + code.globalstate.use_utility_code( + UtilityCode.load_cached("DivInt", "CMath.c").specialize(self.type)) NumBinopNode.generate_evaluation_code(self, code) self.generate_div_warning_code(code) def generate_div_warning_code(self, code): - in_nogil = self.in_nogil_context + in_nogil = self.in_nogil_context if not self.type.is_pyobject: if self.zerodivision_check: if not self.infix: @@ -11586,62 +11586,62 @@ class DivNode(NumBinopNode): else: zero_test = "%s == 0" % self.operand2.result() code.putln("if (unlikely(%s)) {" % zero_test) - if in_nogil: - code.put_ensure_gil() + if in_nogil: + code.put_ensure_gil() code.putln('PyErr_SetString(PyExc_ZeroDivisionError, "%s");' % self.zero_division_message()) - if in_nogil: - code.put_release_ensured_gil() + if in_nogil: + code.put_release_ensured_gil() code.putln(code.error_goto(self.pos)) code.putln("}") if self.type.is_int and self.type.signed and self.operator != '%': - code.globalstate.use_utility_code(UtilityCode.load_cached("UnaryNegOverflows", "Overflow.c")) + code.globalstate.use_utility_code(UtilityCode.load_cached("UnaryNegOverflows", "Overflow.c")) if self.operand2.type.signed == 2: # explicitly signed, no runtime check needed minus1_check = 'unlikely(%s == -1)' % self.operand2.result() else: - type_of_op2 = self.operand2.type.empty_declaration_code() + type_of_op2 = self.operand2.type.empty_declaration_code() minus1_check = '(!(((%s)-1) > 0)) && unlikely(%s == (%s)-1)' % ( type_of_op2, self.operand2.result(), type_of_op2) code.putln("else if (sizeof(%s) == sizeof(long) && %s " " && unlikely(UNARY_NEG_WOULD_OVERFLOW(%s))) {" % ( - self.type.empty_declaration_code(), + self.type.empty_declaration_code(), minus1_check, self.operand1.result())) - if in_nogil: - code.put_ensure_gil() + if in_nogil: + code.put_ensure_gil() code.putln('PyErr_SetString(PyExc_OverflowError, "value too large to perform division");') - if in_nogil: - code.put_release_ensured_gil() + if in_nogil: + code.put_release_ensured_gil() code.putln(code.error_goto(self.pos)) code.putln("}") if code.globalstate.directives['cdivision_warnings'] and self.operator != '/': - code.globalstate.use_utility_code( - UtilityCode.load_cached("CDivisionWarning", "CMath.c")) + code.globalstate.use_utility_code( + UtilityCode.load_cached("CDivisionWarning", "CMath.c")) code.putln("if (unlikely((%s < 0) ^ (%s < 0))) {" % ( self.operand1.result(), self.operand2.result())) - warning_code = "__Pyx_cdivision_warning(%(FILENAME)s, %(LINENO)s)" % { + warning_code = "__Pyx_cdivision_warning(%(FILENAME)s, %(LINENO)s)" % { 'FILENAME': Naming.filename_cname, 'LINENO': Naming.lineno_cname, - } - - if in_nogil: - result_code = 'result' - code.putln("int %s;" % result_code) - code.put_ensure_gil() - code.putln(code.set_error_info(self.pos, used=True)) - code.putln("%s = %s;" % (result_code, warning_code)) - code.put_release_ensured_gil() - else: - result_code = warning_code - code.putln(code.set_error_info(self.pos, used=True)) - - code.put("if (unlikely(%s)) " % result_code) + } + + if in_nogil: + result_code = 'result' + code.putln("int %s;" % result_code) + code.put_ensure_gil() + code.putln(code.set_error_info(self.pos, used=True)) + code.putln("%s = %s;" % (result_code, warning_code)) + code.put_release_ensured_gil() + else: + result_code = warning_code + code.putln(code.set_error_info(self.pos, used=True)) + + code.put("if (unlikely(%s)) " % result_code) code.put_goto(code.error_label) code.putln("}") def calculate_result_code(self): - if self.type.is_complex or self.is_cpp_operation(): + if self.type.is_complex or self.is_cpp_operation(): return NumBinopNode.calculate_result_code(self) elif self.type.is_float and self.operator == '//': return "floor(%s / %s)" % ( @@ -11725,12 +11725,12 @@ class ModNode(DivNode): if not self.type.is_pyobject and not self.cdivision: if self.type.is_int: code.globalstate.use_utility_code( - UtilityCode.load_cached("ModInt", "CMath.c").specialize(self.type)) + UtilityCode.load_cached("ModInt", "CMath.c").specialize(self.type)) else: # float code.globalstate.use_utility_code( - UtilityCode.load_cached("ModFloat", "CMath.c").specialize( + UtilityCode.load_cached("ModFloat", "CMath.c").specialize( self.type, math_h_modifier=self.type.math_h_modifier)) - # NOTE: skipping over DivNode here + # NOTE: skipping over DivNode here NumBinopNode.generate_evaluation_code(self, code) self.generate_div_warning_code(code) @@ -11752,19 +11752,19 @@ class ModNode(DivNode): self.operand2.result()) def py_operation_function(self, code): - type1, type2 = self.operand1.type, self.operand2.type - # ("..." % x) must call "x.__rmod__()" for string subtypes. - if type1 is unicode_type: - if self.operand1.may_be_none() or ( - type2.is_extension_type and type2.subtype_of(type1) or - type2 is py_object_type and not isinstance(self.operand2, CoerceToPyTypeNode)): + type1, type2 = self.operand1.type, self.operand2.type + # ("..." % x) must call "x.__rmod__()" for string subtypes. + if type1 is unicode_type: + if self.operand1.may_be_none() or ( + type2.is_extension_type and type2.subtype_of(type1) or + type2 is py_object_type and not isinstance(self.operand2, CoerceToPyTypeNode)): return '__Pyx_PyUnicode_FormatSafe' else: return 'PyUnicode_Format' - elif type1 is str_type: - if self.operand1.may_be_none() or ( - type2.is_extension_type and type2.subtype_of(type1) or - type2 is py_object_type and not isinstance(self.operand2, CoerceToPyTypeNode)): + elif type1 is str_type: + if self.operand1.may_be_none() or ( + type2.is_extension_type and type2.subtype_of(type1) or + type2 is py_object_type and not isinstance(self.operand2, CoerceToPyTypeNode)): return '__Pyx_PyString_FormatSafe' else: return '__Pyx_PyString_Format' @@ -11780,18 +11780,18 @@ class PowNode(NumBinopNode): if self.type.real_type.is_float: self.operand1 = self.operand1.coerce_to(self.type, env) self.operand2 = self.operand2.coerce_to(self.type, env) - self.pow_func = self.type.binary_op('**') + self.pow_func = self.type.binary_op('**') else: error(self.pos, "complex int powers not supported") self.pow_func = "<error>" elif self.type.is_float: self.pow_func = "pow" + self.type.math_h_modifier elif self.type.is_int: - self.pow_func = "__Pyx_pow_%s" % self.type.empty_declaration_code().replace(' ', '_') + self.pow_func = "__Pyx_pow_%s" % self.type.empty_declaration_code().replace(' ', '_') env.use_utility_code( - UtilityCode.load_cached("IntPow", "CMath.c").specialize( + UtilityCode.load_cached("IntPow", "CMath.c").specialize( func_name=self.pow_func, - type=self.type.empty_declaration_code(), + type=self.type.empty_declaration_code(), signed=self.type.signed and 1 or 0)) elif not self.type.is_error: error(self.pos, "got unexpected types for C power operator: %s, %s" % @@ -11812,7 +11812,7 @@ class PowNode(NumBinopNode): def py_operation_function(self, code): if (self.type.is_pyobject and self.operand1.constant_result == 2 and - isinstance(self.operand1.constant_result, _py_int_types) and + isinstance(self.operand1.constant_result, _py_int_types) and self.operand2.type is py_object_type): code.globalstate.use_utility_code(UtilityCode.load_cached('PyNumberPow2', 'Optimize.c')) if self.inplace: @@ -11913,13 +11913,13 @@ class BoolBinopNode(ExprNode): my_label = and_label = code.new_label('next_and') else: my_label = or_label = code.new_label('next_or') - self.operand1.generate_bool_evaluation_code( + self.operand1.generate_bool_evaluation_code( code, final_result_temp, final_result_type, and_label, or_label, end_label, my_label) and_label, or_label = outer_labels code.put_label(my_label) - self.operand2.generate_bool_evaluation_code( + self.operand2.generate_bool_evaluation_code( code, final_result_temp, final_result_type, and_label, or_label, end_label, fall_through) def generate_evaluation_code(self, code): @@ -11928,7 +11928,7 @@ class BoolBinopNode(ExprNode): or_label = and_label = None end_label = code.new_label('bool_binop_done') self.generate_bool_evaluation_code(code, self.result(), result_type, and_label, or_label, end_label, end_label) - code.put_label(end_label) + code.put_label(end_label) gil_message = "Truth-testing Python object" @@ -12024,43 +12024,43 @@ class BoolBinopResultNode(ExprNode): self.arg.generate_evaluation_code(code) if and_label or or_label: test_result, uses_temp = self.generate_operand_test(code) - if uses_temp and (and_label and or_label): - # cannot become final result => free early - # disposal: uses_temp and (and_label and or_label) - self.arg.generate_disposal_code(code) + if uses_temp and (and_label and or_label): + # cannot become final result => free early + # disposal: uses_temp and (and_label and or_label) + self.arg.generate_disposal_code(code) sense = '!' if or_label else '' code.putln("if (%s%s) {" % (sense, test_result)) if uses_temp: code.funcstate.release_temp(test_result) - if not uses_temp or not (and_label and or_label): - # disposal: (not uses_temp) or {not (and_label and or_label) [if]} - self.arg.generate_disposal_code(code) + if not uses_temp or not (and_label and or_label): + # disposal: (not uses_temp) or {not (and_label and or_label) [if]} + self.arg.generate_disposal_code(code) - if or_label and or_label != fall_through: + if or_label and or_label != fall_through: # value is false => short-circuit to next 'or' code.put_goto(or_label) if and_label: # value is true => go to next 'and' - if or_label: + if or_label: code.putln("} else {") - if not uses_temp: - # disposal: (not uses_temp) and {(and_label and or_label) [else]} - self.arg.generate_disposal_code(code) - if and_label != fall_through: - code.put_goto(and_label) + if not uses_temp: + # disposal: (not uses_temp) and {(and_label and or_label) [else]} + self.arg.generate_disposal_code(code) + if and_label != fall_through: + code.put_goto(and_label) if not and_label or not or_label: # if no next 'and' or 'or', we provide the result - if and_label or or_label: - code.putln("} else {") + if and_label or or_label: + code.putln("} else {") self.value.generate_evaluation_code(code) self.value.make_owned_reference(code) code.putln("%s = %s;" % (final_result_temp, self.value.result_as(final_result_type))) self.value.generate_post_assignment_code(code) - # disposal: {not (and_label and or_label) [else]} + # disposal: {not (and_label and or_label) [else]} self.arg.generate_disposal_code(code) self.value.free_temps(code) - if end_label != fall_through: + if end_label != fall_through: code.put_goto(end_label) if and_label or or_label: @@ -12077,7 +12077,7 @@ class CondExprNode(ExprNode): true_val = None false_val = None - is_temp = True + is_temp = True subexprs = ['test', 'true_val', 'false_val'] @@ -12107,8 +12107,8 @@ class CondExprNode(ExprNode): def analyse_result_type(self, env): self.type = PyrexTypes.independent_spanning_type( self.true_val.type, self.false_val.type) - if self.type.is_reference: - self.type = PyrexTypes.CFakeReferenceType(self.type.ref_base_type) + if self.type.is_reference: + self.type = PyrexTypes.CFakeReferenceType(self.type.ref_base_type) if self.type.is_pyobject: self.result_ctype = py_object_type elif self.true_val.is_ephemeral() or self.false_val.is_ephemeral(): @@ -12116,16 +12116,16 @@ class CondExprNode(ExprNode): if self.true_val.type.is_pyobject or self.false_val.type.is_pyobject: self.true_val = self.true_val.coerce_to(self.type, env) self.false_val = self.false_val.coerce_to(self.type, env) - if self.type.is_error: + if self.type.is_error: self.type_error() return self - def coerce_to_integer(self, env): - self.true_val = self.true_val.coerce_to_integer(env) - self.false_val = self.false_val.coerce_to_integer(env) - self.result_ctype = None - return self.analyse_result_type(env) - + def coerce_to_integer(self, env): + self.true_val = self.true_val.coerce_to_integer(env) + self.false_val = self.false_val.coerce_to_integer(env) + self.result_ctype = None + return self.analyse_result_type(env) + def coerce_to(self, dst_type, env): self.true_val = self.true_val.coerce_to(dst_type, env) self.false_val = self.false_val.coerce_to(dst_type, env) @@ -12202,8 +12202,8 @@ class CmpNode(object): def calculate_cascaded_constant_result(self, operand1_result): func = compile_time_binary_operators[self.operator] operand2_result = self.operand2.constant_result - if (isinstance(operand1_result, any_string_type) and - isinstance(operand2_result, any_string_type) and + if (isinstance(operand1_result, any_string_type) and + isinstance(operand2_result, any_string_type) and type(operand1_result) != type(operand2_result)): # string comparison of different types isn't portable return @@ -12228,7 +12228,7 @@ class CmpNode(object): operand2 = self.operand2.compile_time_value(denv) try: result = func(operand1, operand2) - except Exception as e: + except Exception as e: self.compile_time_value_error(e) result = None if result: @@ -12300,9 +12300,9 @@ class CmpNode(object): if new_common_type is None: # fall back to generic type compatibility tests - if type1.is_ctuple or type2.is_ctuple: - new_common_type = py_object_type - elif type1 == type2: + if type1.is_ctuple or type2.is_ctuple: + new_common_type = py_object_type + elif type1 == type2: new_common_type = type1 elif type1.is_pyobject or type2.is_pyobject: if type2.is_numeric or type2.is_string: @@ -12414,7 +12414,7 @@ class CmpNode(object): if self.operand2.type is Builtin.dict_type: self.operand2 = self.operand2.as_none_safe_node("'NoneType' object is not iterable") self.special_bool_cmp_utility_code = UtilityCode.load_cached("PyDictContains", "ObjectHandling.c") - self.special_bool_cmp_function = "__Pyx_PyDict_ContainsTF" + self.special_bool_cmp_function = "__Pyx_PyDict_ContainsTF" return True elif self.operand2.type is Builtin.set_type: self.operand2 = self.operand2.as_none_safe_node("'NoneType' object is not iterable") @@ -12424,13 +12424,13 @@ class CmpNode(object): elif self.operand2.type is Builtin.unicode_type: self.operand2 = self.operand2.as_none_safe_node("'NoneType' object is not iterable") self.special_bool_cmp_utility_code = UtilityCode.load_cached("PyUnicodeContains", "StringTools.c") - self.special_bool_cmp_function = "__Pyx_PyUnicode_ContainsTF" + self.special_bool_cmp_function = "__Pyx_PyUnicode_ContainsTF" return True else: if not self.operand2.type.is_pyobject: self.operand2 = self.operand2.coerce_to_pyobject(env) self.special_bool_cmp_utility_code = UtilityCode.load_cached("PySequenceContains", "ObjectHandling.c") - self.special_bool_cmp_function = "__Pyx_PySequence_ContainsTF" + self.special_bool_cmp_function = "__Pyx_PySequence_ContainsTF" return True return False @@ -12501,20 +12501,20 @@ class CmpNode(object): common_type = type1 code1 = operand1.result_as(common_type) code2 = operand2.result_as(common_type) - statement = "%s = %s(%s %s %s);" % ( + statement = "%s = %s(%s %s %s);" % ( result_code, coerce_result, code1, self.c_operator(op), - code2) - if self.is_cpp_comparison() and self.exception_check == '+': - translate_cpp_exception( - code, - self.pos, - statement, - result_code if self.type.is_pyobject else None, - self.exception_value, - self.in_nogil_context) + code2) + if self.is_cpp_comparison() and self.exception_check == '+': + translate_cpp_exception( + code, + self.pos, + statement, + result_code if self.type.is_pyobject else None, + self.exception_value, + self.in_nogil_context) else: code.putln(statement) @@ -12658,7 +12658,7 @@ class PrimaryCmpNode(ExprNode, CmpNode): def analyse_cpp_comparison(self, env): type1 = self.operand1.type type2 = self.operand2.type - self.is_pycmp = False + self.is_pycmp = False entry = env.lookup_operator(self.operator, [self.operand1, self.operand2]) if entry is None: error(self.pos, "Invalid types for '%s' (%s, %s)" % @@ -12669,12 +12669,12 @@ class PrimaryCmpNode(ExprNode, CmpNode): func_type = entry.type if func_type.is_ptr: func_type = func_type.base_type - self.exception_check = func_type.exception_check - self.exception_value = func_type.exception_value - if self.exception_check == '+': - self.is_temp = True - if self.exception_value is None: - env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp")) + self.exception_check = func_type.exception_check + self.exception_value = func_type.exception_value + if self.exception_check == '+': + self.is_temp = True + if self.exception_value is None: + env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp")) if len(func_type.args) == 1: self.operand2 = self.operand2.coerce_to(func_type.args[0].type, env) else: @@ -12836,10 +12836,10 @@ class CascadedCmpNode(Node, CmpNode): def has_python_operands(self): return self.operand2.type.is_pyobject - def is_cpp_comparison(self): - # cascaded comparisons aren't currently implemented for c++ classes. - return False - + def is_cpp_comparison(self): + # cascaded comparisons aren't currently implemented for c++ classes. + return False + def optimise_comparison(self, operand1, env, result_is_bool=False): if self.find_special_bool_compare_function(env, operand1, result_is_bool): self.is_pycmp = False @@ -12912,19 +12912,19 @@ binop_node_classes = { "**": PowNode, } - -def binop_node(pos, operator, operand1, operand2, inplace=False, **kwargs): + +def binop_node(pos, operator, operand1, operand2, inplace=False, **kwargs): # Construct binop node of appropriate class for # given operator. - return binop_node_classes[operator]( - pos, - operator=operator, - operand1=operand1, - operand2=operand2, - inplace=inplace, - **kwargs) - - + return binop_node_classes[operator]( + pos, + operator=operator, + operand1=operand1, + operand2=operand2, + inplace=inplace, + **kwargs) + + #------------------------------------------------------------------- # # Coercion nodes @@ -12961,7 +12961,7 @@ class CoercionNode(ExprNode): code.annotate((file, line, col-1), AnnotationItem( style='coerce', tag='coerce', text='[%s] to [%s]' % (self.arg.type, self.type))) - + class CoerceToMemViewSliceNode(CoercionNode): """ Coerce an object to a memoryview slice. This holds a new reference in @@ -13190,7 +13190,7 @@ class CoerceToPyTypeNode(CoercionNode): # to a Python object. type = py_object_type - target_type = py_object_type + target_type = py_object_type is_temp = 1 def __init__(self, arg, env, type=py_object_type): @@ -13210,17 +13210,17 @@ class CoerceToPyTypeNode(CoercionNode): self.type = unicode_type elif arg.type.is_complex: self.type = Builtin.complex_type - self.target_type = self.type + self.target_type = self.type elif arg.type.is_string or arg.type.is_cpp_string: if (type not in (bytes_type, bytearray_type) and not env.directives['c_string_encoding']): error(arg.pos, "default encoding required for conversion from '%s' to '%s'" % (arg.type, type)) - self.type = self.target_type = type + self.type = self.target_type = type else: # FIXME: check that the target type and the resulting type are compatible - self.target_type = type + self.target_type = type gil_message = "Converting to Python object" @@ -13248,11 +13248,11 @@ class CoerceToPyTypeNode(CoercionNode): return self def generate_result_code(self, code): - code.putln('%s; %s' % ( - self.arg.type.to_py_call_code( - self.arg.result(), - self.result(), - self.target_type), + code.putln('%s; %s' % ( + self.arg.type.to_py_call_code( + self.arg.result(), + self.result(), + self.target_type), code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) @@ -13320,7 +13320,7 @@ class CoerceFromPyTypeNode(CoercionNode): return self def is_ephemeral(self): - return (self.type.is_ptr and not self.type.is_array) and self.arg.is_ephemeral() + return (self.type.is_ptr and not self.type.is_array) and self.arg.is_ephemeral() def generate_result_code(self, code): from_py_function = None @@ -13330,7 +13330,7 @@ class CoerceFromPyTypeNode(CoercionNode): from_py_function = '__Pyx_PyBytes' + self.type.from_py_function[len('__Pyx_PyObject'):] NoneCheckNode.generate_if_needed(self.arg, code, "expected bytes, NoneType found") - code.putln(self.type.from_py_call_code( + code.putln(self.type.from_py_call_code( self.arg.py_result(), self.result(), self.pos, code, from_py_function=from_py_function)) if self.type.is_pyobject: code.put_gotref(self.py_result()) @@ -13346,14 +13346,14 @@ class CoerceToBooleanNode(CoercionNode): type = PyrexTypes.c_bint_type _special_builtins = { - Builtin.list_type: 'PyList_GET_SIZE', - Builtin.tuple_type: 'PyTuple_GET_SIZE', - Builtin.set_type: 'PySet_GET_SIZE', - Builtin.frozenset_type: 'PySet_GET_SIZE', - Builtin.bytes_type: 'PyBytes_GET_SIZE', + Builtin.list_type: 'PyList_GET_SIZE', + Builtin.tuple_type: 'PyTuple_GET_SIZE', + Builtin.set_type: 'PySet_GET_SIZE', + Builtin.frozenset_type: 'PySet_GET_SIZE', + Builtin.bytes_type: 'PyBytes_GET_SIZE', Builtin.bytearray_type: 'PyByteArray_GET_SIZE', - Builtin.unicode_type: '__Pyx_PyUnicode_IS_TRUE', - } + Builtin.unicode_type: '__Pyx_PyUnicode_IS_TRUE', + } def __init__(self, arg, env): CoercionNode.__init__(self, arg) @@ -13390,7 +13390,7 @@ class CoerceToBooleanNode(CoercionNode): self.arg.py_result(), code.error_goto_if_neg(self.result(), self.pos))) - + class CoerceToComplexNode(CoercionNode): def __init__(self, arg, dst_type, env): diff --git a/contrib/tools/cython/Cython/Compiler/FlowControl.pxd b/contrib/tools/cython/Cython/Compiler/FlowControl.pxd index 1b855455f7..c87370b819 100644 --- a/contrib/tools/cython/Cython/Compiler/FlowControl.pxd +++ b/contrib/tools/cython/Cython/Compiler/FlowControl.pxd @@ -12,7 +12,7 @@ cdef class ControlBlock: cdef public dict gen cdef public set bounded - # Big integer bitsets + # Big integer bitsets cdef public object i_input cdef public object i_output cdef public object i_gen @@ -87,11 +87,11 @@ cdef class Uninitialized: cdef class Unknown: pass - -cdef class MessageCollection: - cdef set messages - - + +cdef class MessageCollection: + cdef set messages + + @cython.locals(dirty=bint, block=ControlBlock, parent=ControlBlock, assmt=NameAssignment) cdef check_definitions(ControlFlow flow, dict compiler_directives) @@ -99,7 +99,7 @@ cdef check_definitions(ControlFlow flow, dict compiler_directives) @cython.final cdef class ControlFlowAnalysis(CythonTransform): cdef object gv_ctx - cdef object constant_folder + cdef object constant_folder cdef set reductions cdef list env_stack cdef list stack diff --git a/contrib/tools/cython/Cython/Compiler/FlowControl.py b/contrib/tools/cython/Cython/Compiler/FlowControl.py index 7e8270b198..df04471f90 100644 --- a/contrib/tools/cython/Cython/Compiler/FlowControl.py +++ b/contrib/tools/cython/Cython/Compiler/FlowControl.py @@ -2,7 +2,7 @@ from __future__ import absolute_import import cython cython.declare(PyrexTypes=object, ExprNodes=object, Nodes=object, - Builtin=object, InternalError=object, error=object, warning=object, + Builtin=object, InternalError=object, error=object, warning=object, py_object_type=object, unspecified_type=object, object_expr=object, fake_rhs_expr=object, TypedExprNode=object) @@ -15,9 +15,9 @@ from . import PyrexTypes from .Visitor import TreeVisitor, CythonTransform from .Errors import error, warning, InternalError -from .Optimize import ConstantFolding +from .Optimize import ConstantFolding + - class TypedExprNode(ExprNodes.ExprNode): # Used for declaring assignments of a specified type without a known entry. def __init__(self, type, may_be_none=None, pos=None): @@ -256,7 +256,7 @@ class ControlFlow(object): for entry in block.bounded: block.i_kill |= self.assmts[entry].bit - for assmts in self.assmts.values(): + for assmts in self.assmts.values(): self.entry_point.i_gen |= assmts.bit self.entry_point.i_output = self.entry_point.i_gen @@ -486,11 +486,11 @@ class GV(object): if annotate_defs: for stat in block.stats: if isinstance(stat, NameAssignment): - label += '\n %s [%s %s]' % ( - stat.entry.name, 'deletion' if stat.is_deletion else 'definition', stat.pos[1]) + label += '\n %s [%s %s]' % ( + stat.entry.name, 'deletion' if stat.is_deletion else 'definition', stat.pos[1]) elif isinstance(stat, NameReference): if stat.entry: - label += '\n %s [reference %s]' % (stat.entry.name, stat.pos[1]) + label += '\n %s [reference %s]' % (stat.entry.name, stat.pos[1]) if not label: label = 'empty' pid = ctx.nodeid(block) @@ -505,16 +505,16 @@ class GV(object): class MessageCollection(object): """Collect error/warnings messages first then sort""" def __init__(self): - self.messages = set() + self.messages = set() def error(self, pos, message): - self.messages.add((pos, True, message)) + self.messages.add((pos, True, message)) def warning(self, pos, message): - self.messages.add((pos, False, message)) + self.messages.add((pos, False, message)) def report(self): - for pos, is_error, message in sorted(self.messages): + for pos, is_error, message in sorted(self.messages): if is_error: error(pos, message) else: @@ -582,14 +582,14 @@ def check_definitions(flow, compiler_directives): node.cf_maybe_null = False # Find uninitialized references and cf-hints - for node, entry in references.items(): + for node, entry in references.items(): if Uninitialized in node.cf_state: node.cf_maybe_null = True if not entry.from_closure and len(node.cf_state) == 1: node.cf_is_null = True if (node.allow_null or entry.from_closure - or entry.is_pyclass_attr or entry.type.is_error): - pass # Can be uninitialized here + or entry.is_pyclass_attr or entry.type.is_error): + pass # Can be uninitialized here elif node.cf_is_null: if entry.error_on_uninitialized or ( Options.error_on_uninitialized and ( @@ -635,7 +635,7 @@ def check_definitions(flow, compiler_directives): for entry in flow.entries: if (not entry.cf_references and not entry.is_pyclass_attr): - if entry.name != '_' and not entry.name.startswith('unused'): + if entry.name != '_' and not entry.name.startswith('unused'): # '_' is often used for unused variables, e.g. in loops if entry.is_arg: if warn_unused_arg: @@ -675,7 +675,7 @@ class ControlFlowAnalysis(CythonTransform): def visit_ModuleNode(self, node): self.gv_ctx = GVContext() - self.constant_folder = ConstantFolding() + self.constant_folder = ConstantFolding() # Set of NameNode reductions self.reductions = set() @@ -778,13 +778,13 @@ class ControlFlowAnalysis(CythonTransform): if entry is None: # TODO: This shouldn't happen... return self.flow.mark_assignment(lhs, rhs, entry) - elif lhs.is_sequence_constructor: - for i, arg in enumerate(lhs.args): - if not rhs or arg.is_starred: - item_node = None - else: - item_node = rhs.inferable_item_node(i) - self.mark_assignment(arg, item_node) + elif lhs.is_sequence_constructor: + for i, arg in enumerate(lhs.args): + if not rhs or arg.is_starred: + item_node = None + else: + item_node = rhs.inferable_item_node(i) + self.mark_assignment(arg, item_node) else: self._visit(lhs) @@ -832,7 +832,7 @@ class ControlFlowAnalysis(CythonTransform): self.in_inplace_assignment = True self.visitchildren(node) self.in_inplace_assignment = False - self.mark_assignment(node.lhs, self.constant_folder(node.create_binop_node())) + self.mark_assignment(node.lhs, self.constant_folder(node.create_binop_node())) return node def visit_DelStatNode(self, node): @@ -843,8 +843,8 @@ class ControlFlowAnalysis(CythonTransform): error(arg.pos, "can not delete variable '%s' " "referenced in nested scope" % entry.name) - if not node.ignore_nonexisting: - self._visit(arg) # mark reference + if not node.ignore_nonexisting: + self._visit(arg) # mark reference self.flow.mark_deletion(arg, entry) else: self._visit(arg) @@ -981,11 +981,11 @@ class ControlFlowAnalysis(CythonTransform): for arg in sequence.args[:2]: self.mark_assignment(target, arg) if len(sequence.args) > 2: - self.mark_assignment(target, self.constant_folder( + self.mark_assignment(target, self.constant_folder( ExprNodes.binop_node(node.pos, '+', sequence.args[0], - sequence.args[2]))) + sequence.args[2]))) if not is_special: # A for-loop basically translates to subsequent calls to @@ -996,9 +996,9 @@ class ControlFlowAnalysis(CythonTransform): self.mark_assignment(target, node.item) - def visit_AsyncForStatNode(self, node): - return self.visit_ForInStatNode(node) - + def visit_AsyncForStatNode(self, node): + return self.visit_ForInStatNode(node) + def visit_ForInStatNode(self, node): condition_block = self.flow.nextblock() next_block = self.flow.newblock() @@ -1010,9 +1010,9 @@ class ControlFlowAnalysis(CythonTransform): if isinstance(node, Nodes.ForInStatNode): self.mark_forloop_target(node) - elif isinstance(node, Nodes.AsyncForStatNode): - # not entirely correct, but good enough for now - self.mark_assignment(node.target, node.item) + elif isinstance(node, Nodes.AsyncForStatNode): + # not entirely correct, but good enough for now + self.mark_assignment(node.target, node.item) else: # Parallel self.mark_assignment(node.target) @@ -1090,8 +1090,8 @@ class ControlFlowAnalysis(CythonTransform): self.flow.nextblock() self.mark_assignment(node.target, node.bound1) if node.step is not None: - self.mark_assignment(node.target, self.constant_folder( - ExprNodes.binop_node(node.pos, '+', node.bound1, node.step))) + self.mark_assignment(node.target, self.constant_folder( + ExprNodes.binop_node(node.pos, '+', node.bound1, node.step))) # Body block self.flow.nextblock() self._visit(node.body) @@ -1182,7 +1182,7 @@ class ControlFlowAnalysis(CythonTransform): # Exception entry point entry_point = self.flow.newblock() self.flow.block = entry_point - self._visit(node.finally_except_clause) + self._visit(node.finally_except_clause) if self.flow.block and self.flow.exceptions: self.flow.block.add_child(self.flow.exceptions[-1].entry_point) diff --git a/contrib/tools/cython/Cython/Compiler/FusedNode.py b/contrib/tools/cython/Cython/Compiler/FusedNode.py index 5b743b51f9..26d6ffd3d6 100644 --- a/contrib/tools/cython/Cython/Compiler/FusedNode.py +++ b/contrib/tools/cython/Cython/Compiler/FusedNode.py @@ -93,8 +93,8 @@ class FusedCFuncDefNode(StatListNode): for cname, fused_to_specific in permutations: copied_node = copy.deepcopy(self.node) - # keep signature object identity for special casing in DefNode.analyse_declarations() - copied_node.entry.signature = self.node.entry.signature + # keep signature object identity for special casing in DefNode.analyse_declarations() + copied_node.entry.signature = self.node.entry.signature self._specialize_function_args(copied_node.args, fused_to_specific) copied_node.return_type = self.node.return_type.specialize( @@ -219,7 +219,7 @@ class FusedCFuncDefNode(StatListNode): if arg.type.is_fused: arg.type = arg.type.specialize(fused_to_specific) if arg.type.is_memoryviewslice: - arg.type.validate_memslice_dtype(arg.pos) + arg.type.validate_memslice_dtype(arg.pos) def create_new_local_scope(self, node, env, f2s): """ @@ -281,14 +281,14 @@ class FusedCFuncDefNode(StatListNode): """ for specialized_type in normal_types: # all_numeric = all_numeric and specialized_type.is_numeric - pyx_code.context.update( - py_type_name=specialized_type.py_type_name(), - specialized_type_name=specialized_type.specialization_string, - ) + pyx_code.context.update( + py_type_name=specialized_type.py_type_name(), + specialized_type_name=specialized_type.specialization_string, + ) pyx_code.put_chunk( u""" - if isinstance(arg, {{py_type_name}}): - dest_sig[{{dest_sig_idx}}] = '{{specialized_type_name}}'; break + if isinstance(arg, {{py_type_name}}): + dest_sig[{{dest_sig_idx}}] = '{{specialized_type_name}}'; break """) def _dtype_name(self, dtype): @@ -418,27 +418,27 @@ class FusedCFuncDefNode(StatListNode): to each specialization, which obtains the buffer each time and tries to match the format string. """ - # The first thing to find a match in this loop breaks out of the loop - pyx_code.put_chunk( - u""" + # The first thing to find a match in this loop breaks out of the loop + pyx_code.put_chunk( + u""" """ + (u"arg_is_pythran_compatible = False" if pythran_types else u"") + u""" - if ndarray is not None: - if isinstance(arg, ndarray): - dtype = arg.dtype + if ndarray is not None: + if isinstance(arg, ndarray): + dtype = arg.dtype """ + (u"arg_is_pythran_compatible = True" if pythran_types else u"") + u""" - elif __pyx_memoryview_check(arg): - arg_base = arg.base - if isinstance(arg_base, ndarray): - dtype = arg_base.dtype - else: - dtype = None - else: - dtype = None - - itemsize = -1 - if dtype is not None: - itemsize = dtype.itemsize - kind = ord(dtype.kind) + elif __pyx_memoryview_check(arg): + arg_base = arg.base + if isinstance(arg_base, ndarray): + dtype = arg_base.dtype + else: + dtype = None + else: + dtype = None + + itemsize = -1 + if dtype is not None: + itemsize = dtype.itemsize + kind = ord(dtype.kind) dtype_signed = kind == 'i' """) pyx_code.indent(2) @@ -463,13 +463,13 @@ class FusedCFuncDefNode(StatListNode): else: arg_is_pythran_compatible = not (arg.flags.f_contiguous and (<Py_ssize_t>arg.ndim) > 1) """) - pyx_code.named_insertion_point("numpy_dtype_checks") + pyx_code.named_insertion_point("numpy_dtype_checks") self._buffer_check_numpy_dtype(pyx_code, buffer_types, pythran_types) - pyx_code.dedent(2) + pyx_code.dedent(2) - for specialized_type in buffer_types: - self._buffer_parse_format_string_check( - pyx_code, decl_code, specialized_type, env) + for specialized_type in buffer_types: + self._buffer_parse_format_string_check( + pyx_code, decl_code, specialized_type, env) def _buffer_declarations(self, pyx_code, decl_code, all_buffer_types, pythran_types): """ @@ -535,23 +535,23 @@ class FusedCFuncDefNode(StatListNode): Specialize fused types and split into normal types and buffer types. """ specialized_types = PyrexTypes.get_specialized_types(arg.type) - - # Prefer long over int, etc by sorting (see type classes in PyrexTypes.py) - specialized_types.sort() - + + # Prefer long over int, etc by sorting (see type classes in PyrexTypes.py) + specialized_types.sort() + seen_py_type_names = set() normal_types, buffer_types, pythran_types = [], [], [] - has_object_fallback = False + has_object_fallback = False for specialized_type in specialized_types: py_type_name = specialized_type.py_type_name() if py_type_name: if py_type_name in seen_py_type_names: continue seen_py_type_names.add(py_type_name) - if py_type_name == 'object': - has_object_fallback = True - else: - normal_types.append(specialized_type) + if py_type_name == 'object': + has_object_fallback = True + else: + normal_types.append(specialized_type) elif specialized_type.is_pythran_expr: pythran_types.append(specialized_type) elif specialized_type.is_buffer or specialized_type.is_memoryviewslice: @@ -620,7 +620,7 @@ class FusedCFuncDefNode(StatListNode): # FIXME: use a typed signature - currently fails badly because # default arguments inherit the types we specify here! - dest_sig = [None] * {{n_fused}} + dest_sig = [None] * {{n_fused}} if kwargs is not None and not kwargs: kwargs = None @@ -659,22 +659,22 @@ class FusedCFuncDefNode(StatListNode): normal_types, buffer_types, pythran_types, has_object_fallback = self._split_fused_types(arg) self._unpack_argument(pyx_code) - - # 'unrolled' loop, first match breaks out of it - if pyx_code.indenter("while 1:"): - if normal_types: - self._fused_instance_checks(normal_types, pyx_code, env) + + # 'unrolled' loop, first match breaks out of it + if pyx_code.indenter("while 1:"): + if normal_types: + self._fused_instance_checks(normal_types, pyx_code, env) if buffer_types or pythran_types: env.use_utility_code(Code.UtilityCode.load_cached("IsLittleEndian", "ModuleSetupCode.c")) self._buffer_checks(buffer_types, pythran_types, pyx_code, decl_code, env) - if has_object_fallback: - pyx_code.context.update(specialized_type_name='object') - pyx_code.putln(self.match) - else: - pyx_code.putln(self.no_match) - pyx_code.putln("break") - pyx_code.dedent() - + if has_object_fallback: + pyx_code.context.update(specialized_type_name='object') + pyx_code.putln(self.match) + else: + pyx_code.putln(self.no_match) + pyx_code.putln("break") + pyx_code.dedent() + fused_index += 1 all_buffer_types.update(buffer_types) all_buffer_types.update(ty.org_buffer for ty in pythran_types) @@ -716,14 +716,14 @@ class FusedCFuncDefNode(StatListNode): fragment_code = pyx_code.getvalue() # print decl_code.getvalue() # print fragment_code - from .Optimize import ConstantFolding - fragment = TreeFragment.TreeFragment( - fragment_code, level='module', pipeline=[ConstantFolding()]) + from .Optimize import ConstantFolding + fragment = TreeFragment.TreeFragment( + fragment_code, level='module', pipeline=[ConstantFolding()]) ast = TreeFragment.SetPosTransform(self.node.pos)(fragment.root) UtilityCode.declare_declarations_in_scope( decl_code.getvalue(), env.global_scope()) ast.scope = env - # FIXME: for static methods of cdef classes, we build the wrong signature here: first arg becomes 'self' + # FIXME: for static methods of cdef classes, we build the wrong signature here: first arg becomes 'self' ast.analyse_declarations(env) py_func = ast.stats[-1] # the DefNode self.fragment_scope = ast.scope @@ -806,7 +806,7 @@ class FusedCFuncDefNode(StatListNode): if self.py_func: args = [CloneNode(default) for default in defaults if default] self.defaults_tuple = TupleNode(self.pos, args=args) - self.defaults_tuple = self.defaults_tuple.analyse_types(env, skip_children=True).coerce_to_pyobject(env) + self.defaults_tuple = self.defaults_tuple.analyse_types(env, skip_children=True).coerce_to_pyobject(env) self.defaults_tuple = ProxyNode(self.defaults_tuple) self.code_object = ProxyNode(self.specialized_pycfuncs[0].code_object) @@ -829,15 +829,15 @@ class FusedCFuncDefNode(StatListNode): else: nodes = self.nodes - signatures = [StringEncoding.EncodedString(node.specialized_signature_string) - for node in nodes] + signatures = [StringEncoding.EncodedString(node.specialized_signature_string) + for node in nodes] keys = [ExprNodes.StringNode(node.pos, value=sig) - for node, sig in zip(nodes, signatures)] - values = [ExprNodes.PyCFunctionNode.from_defnode(node, binding=True) - for node in nodes] + for node, sig in zip(nodes, signatures)] + values = [ExprNodes.PyCFunctionNode.from_defnode(node, binding=True) + for node in nodes] + + self.__signatures__ = ExprNodes.DictNode.from_pairs(self.pos, zip(keys, values)) - self.__signatures__ = ExprNodes.DictNode.from_pairs(self.pos, zip(keys, values)) - self.specialized_pycfuncs = values for pycfuncnode in values: pycfuncnode.is_specialization = True diff --git a/contrib/tools/cython/Cython/Compiler/Future.py b/contrib/tools/cython/Cython/Compiler/Future.py index af9f55260e..848792e00b 100644 --- a/contrib/tools/cython/Cython/Compiler/Future.py +++ b/contrib/tools/cython/Cython/Compiler/Future.py @@ -4,12 +4,12 @@ def _get_feature(name): return getattr(__future__, name, object()) unicode_literals = _get_feature("unicode_literals") -with_statement = _get_feature("with_statement") # dummy +with_statement = _get_feature("with_statement") # dummy division = _get_feature("division") print_function = _get_feature("print_function") absolute_import = _get_feature("absolute_import") nested_scopes = _get_feature("nested_scopes") # dummy generators = _get_feature("generators") # dummy -generator_stop = _get_feature("generator_stop") +generator_stop = _get_feature("generator_stop") del _get_feature diff --git a/contrib/tools/cython/Cython/Compiler/Lexicon.py b/contrib/tools/cython/Cython/Compiler/Lexicon.py index f88cfa8d5a..72c9ceaefd 100644 --- a/contrib/tools/cython/Cython/Compiler/Lexicon.py +++ b/contrib/tools/cython/Cython/Compiler/Lexicon.py @@ -3,11 +3,11 @@ # Cython Scanner - Lexical Definitions # -from __future__ import absolute_import, unicode_literals +from __future__ import absolute_import, unicode_literals raw_prefixes = "rR" bytes_prefixes = "bB" -string_prefixes = "fFuU" + bytes_prefixes +string_prefixes = "fFuU" + bytes_prefixes char_prefixes = "cC" any_string_prefix = raw_prefixes + string_prefixes + char_prefixes IDENT = 'IDENT' @@ -26,25 +26,25 @@ def make_lexicon(): hexdigit = Any("0123456789ABCDEFabcdef") indentation = Bol + Rep(Any(" \t")) - def underscore_digits(d): - return Rep1(d) + Rep(Str("_") + Rep1(d)) - - decimal = underscore_digits(digit) + def underscore_digits(d): + return Rep1(d) + Rep(Str("_") + Rep1(d)) + + decimal = underscore_digits(digit) dot = Str(".") exponent = Any("Ee") + Opt(Any("+-")) + decimal decimal_fract = (decimal + dot + Opt(decimal)) | (dot + decimal) name = letter + Rep(letter | digit) - intconst = decimal | (Str("0") + ((Any("Xx") + underscore_digits(hexdigit)) | - (Any("Oo") + underscore_digits(octdigit)) | - (Any("Bb") + underscore_digits(bindigit)) )) + intconst = decimal | (Str("0") + ((Any("Xx") + underscore_digits(hexdigit)) | + (Any("Oo") + underscore_digits(octdigit)) | + (Any("Bb") + underscore_digits(bindigit)) )) intsuffix = (Opt(Any("Uu")) + Opt(Any("Ll")) + Opt(Any("Ll"))) | (Opt(Any("Ll")) + Opt(Any("Ll")) + Opt(Any("Uu"))) intliteral = intconst + intsuffix fltconst = (decimal_fract + Opt(exponent)) | (decimal + exponent) imagconst = (intconst | fltconst) + Any("jJ") - # invalid combinations of prefixes are caught in p_string_literal - beginstring = Opt(Rep(Any(string_prefixes + raw_prefixes)) | + # invalid combinations of prefixes are caught in p_string_literal + beginstring = Opt(Rep(Any(string_prefixes + raw_prefixes)) | Any(char_prefixes) ) + (Str("'") | Str('"') | Str("'''") | Str('"""')) two_oct = octdigit + octdigit @@ -70,9 +70,9 @@ def make_lexicon(): return Lexicon([ (name, IDENT), - (intliteral, Method('strip_underscores', symbol='INT')), - (fltconst, Method('strip_underscores', symbol='FLOAT')), - (imagconst, Method('strip_underscores', symbol='IMAG')), + (intliteral, Method('strip_underscores', symbol='INT')), + (fltconst, Method('strip_underscores', symbol='FLOAT')), + (imagconst, Method('strip_underscores', symbol='IMAG')), (punct | diphthong, TEXT), (bra, Method('open_bracket_action')), diff --git a/contrib/tools/cython/Cython/Compiler/Main.py b/contrib/tools/cython/Cython/Compiler/Main.py index 78b5131e6e..af873843b5 100644 --- a/contrib/tools/cython/Cython/Compiler/Main.py +++ b/contrib/tools/cython/Cython/Compiler/Main.py @@ -7,39 +7,39 @@ from __future__ import absolute_import import os import re import sys -import io +import io if sys.version_info[:2] < (2, 6) or (3, 0) <= sys.version_info[:2] < (3, 3): sys.stderr.write("Sorry, Cython requires Python 2.6+ or 3.3+, found %d.%d\n" % tuple(sys.version_info[:2])) sys.exit(1) -try: - from __builtin__ import basestring -except ImportError: - basestring = str - +try: + from __builtin__ import basestring +except ImportError: + basestring = str + # Do not import Parsing here, import it when needed, because Parsing imports # Nodes, which globally needs debug command line options initialized to set a # conditional metaclass. These options are processed by CmdLine called from # main() in this file. # import Parsing from . import Errors -from .StringEncoding import EncodedString +from .StringEncoding import EncodedString from .Scanning import PyrexScanner, FileSourceDescriptor from .Errors import PyrexError, CompileError, error, warning from .Symtab import ModuleScope from .. import Utils from . import Options -from . import Version # legacy import needed by old PyTables versions -version = Version.version # legacy attribute - use "Cython.__version__" instead - +from . import Version # legacy import needed by old PyTables versions +version = Version.version # legacy attribute - use "Cython.__version__" instead + module_name_pattern = re.compile(r"[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)*$") verbose = 0 -standard_include_path = os.path.abspath(os.path.join(os.path.dirname(__file__), - os.path.pardir, 'Includes')) +standard_include_path = os.path.abspath(os.path.join(os.path.dirname(__file__), + os.path.pardir, 'Includes')) class CompilationData(object): # Bundles the information that is passed from transform to transform. @@ -69,10 +69,10 @@ class Context(object): # language_level int currently 2 or 3 for Python 2/3 cython_scope = None - language_level = None # warn when not set but default to Py2 + language_level = None # warn when not set but default to Py2 def __init__(self, include_directories, compiler_directives, cpp=False, - language_level=None, options=None): + language_level=None, options=None): # cython_scope is a hack, set to False by subclasses, in order to break # an infinite loop. # Better code organization would fix it. @@ -87,51 +87,51 @@ class Context(object): self.cpp = cpp self.options = options - self.pxds = {} # full name -> node tree - self._interned = {} # (type(value), value, *key_args) -> interned_value + self.pxds = {} # full name -> node tree + self._interned = {} # (type(value), value, *key_args) -> interned_value - if language_level is not None: - self.set_language_level(language_level) + if language_level is not None: + self.set_language_level(language_level) self.gdb_debug_outputwriter = None def set_language_level(self, level): - from .Future import print_function, unicode_literals, absolute_import, division - future_directives = set() - if level == '3str': - level = 3 - else: - level = int(level) - if level >= 3: - future_directives.add(unicode_literals) - if level >= 3: - future_directives.update([print_function, absolute_import, division]) + from .Future import print_function, unicode_literals, absolute_import, division + future_directives = set() + if level == '3str': + level = 3 + else: + level = int(level) + if level >= 3: + future_directives.add(unicode_literals) + if level >= 3: + future_directives.update([print_function, absolute_import, division]) self.language_level = level - self.future_directives = future_directives + self.future_directives = future_directives if level >= 3: self.modules['builtins'] = self.modules['__builtin__'] - def intern_ustring(self, value, encoding=None): - key = (EncodedString, value, encoding) - try: - return self._interned[key] - except KeyError: - pass - value = EncodedString(value) - if encoding: - value.encoding = encoding - self._interned[key] = value - return value - - def intern_value(self, value, *key): - key = (type(value), value) + key - try: - return self._interned[key] - except KeyError: - pass - self._interned[key] = value - return value - + def intern_ustring(self, value, encoding=None): + key = (EncodedString, value, encoding) + try: + return self._interned[key] + except KeyError: + pass + value = EncodedString(value) + if encoding: + value.encoding = encoding + self._interned[key] = value + return value + + def intern_value(self, value, *key): + key = (type(value), value) + key + try: + return self._interned[key] + except KeyError: + pass + self._interned[key] = value + return value + # pipeline creation functions can now be found in Pipeline.py def process_pxd(self, source_desc, scope, module_name): @@ -149,8 +149,8 @@ class Context(object): def nonfatal_error(self, exc): return Errors.report_error(exc) - def find_module(self, module_name, relative_to=None, pos=None, need_pxd=1, - absolute_fallback=True): + def find_module(self, module_name, relative_to=None, pos=None, need_pxd=1, + absolute_fallback=True): # Finds and returns the module scope corresponding to # the given relative or absolute module name. If this # is the first time the module has been requested, finds @@ -161,27 +161,27 @@ class Context(object): debug_find_module = 0 if debug_find_module: print("Context.find_module: module_name = %s, relative_to = %s, pos = %s, need_pxd = %s" % ( - module_name, relative_to, pos, need_pxd)) + module_name, relative_to, pos, need_pxd)) scope = None pxd_pathname = None if relative_to: - if module_name: - # from .module import ... - qualified_name = relative_to.qualify_name(module_name) - else: - # from . import ... - qualified_name = relative_to.qualified_name - scope = relative_to - relative_to = None - else: - qualified_name = module_name - - if not module_name_pattern.match(qualified_name): - raise CompileError(pos or (module_name, 0, 0), - "'%s' is not a valid module name" % module_name) - - if relative_to: + if module_name: + # from .module import ... + qualified_name = relative_to.qualify_name(module_name) + else: + # from . import ... + qualified_name = relative_to.qualified_name + scope = relative_to + relative_to = None + else: + qualified_name = module_name + + if not module_name_pattern.match(qualified_name): + raise CompileError(pos or (module_name, 0, 0), + "'%s' is not a valid module name" % module_name) + + if relative_to: if debug_find_module: print("...trying relative import") scope = relative_to.lookup_submodule(module_name) @@ -192,12 +192,12 @@ class Context(object): if not scope: if debug_find_module: print("...trying absolute import") - if absolute_fallback: - qualified_name = module_name + if absolute_fallback: + qualified_name = module_name scope = self - for name in qualified_name.split("."): + for name in qualified_name.split("."): scope = scope.find_submodule(name) - + if debug_find_module: print("...scope = %s" % scope) if not scope.pxd_file_loaded: @@ -210,16 +210,16 @@ class Context(object): if debug_find_module: print("......found %s" % pxd_pathname) if not pxd_pathname and need_pxd: - # Set pxd_file_loaded such that we don't need to - # look for the non-existing pxd file next time. - scope.pxd_file_loaded = True - package_pathname = self.search_include_directories(qualified_name, ".py", pos) + # Set pxd_file_loaded such that we don't need to + # look for the non-existing pxd file next time. + scope.pxd_file_loaded = True + package_pathname = self.search_include_directories(qualified_name, ".py", pos) if package_pathname and package_pathname.endswith('__init__.py'): pass else: - error(pos, "'%s.pxd' not found" % qualified_name.replace('.', os.sep)) + error(pos, "'%s.pxd' not found" % qualified_name.replace('.', os.sep)) if pxd_pathname: - scope.pxd_file_loaded = True + scope.pxd_file_loaded = True try: if debug_find_module: print("Context.find_module: Parsing %s" % pxd_pathname) @@ -229,7 +229,7 @@ class Context(object): if Options.source_root: rel_path = os.path.relpath(pxd_pathname, Options.source_root) source_desc = FileSourceDescriptor(pxd_pathname, rel_path) - err, result = self.process_pxd(source_desc, scope, qualified_name) + err, result = self.process_pxd(source_desc, scope, qualified_name) if err: raise err (pxd_codenodes, pxd_scope) = result @@ -239,15 +239,15 @@ class Context(object): return scope def find_pxd_file(self, qualified_name, pos, sys_path=False): - # Search include path (and sys.path if sys_path is True) for - # the .pxd file corresponding to the given fully-qualified - # module name. + # Search include path (and sys.path if sys_path is True) for + # the .pxd file corresponding to the given fully-qualified + # module name. # Will find either a dotted filename or a file in a # package directory. If a source file position is given, # the directory containing the source file is searched first # for a dotted filename, and its containing package root # directory is searched first for a non-dotted filename. - pxd = self.search_include_directories(qualified_name, ".pxd", pos, sys_path=sys_path) + pxd = self.search_include_directories(qualified_name, ".pxd", pos, sys_path=sys_path) if pxd is None: # XXX Keep this until Includes/Deprecated is removed if (qualified_name.startswith('python') or qualified_name in ('stdlib', 'stdio', 'stl')): @@ -287,13 +287,13 @@ class Context(object): def search_include_directories(self, qualified_name, suffix, pos, include=False, sys_path=False): - include_dirs = self.include_directories - if sys_path: - include_dirs = include_dirs + sys.path - # include_dirs must be hashable for caching in @cached_function - include_dirs = tuple(include_dirs + [standard_include_path]) - return search_include_directories(include_dirs, qualified_name, - suffix, pos, include) + include_dirs = self.include_directories + if sys_path: + include_dirs = include_dirs + sys.path + # include_dirs must be hashable for caching in @cached_function + include_dirs = tuple(include_dirs + [standard_include_path]) + return search_include_directories(include_dirs, qualified_name, + suffix, pos, include) def find_root_package_dir(self, file_path): return Utils.find_root_package_dir(file_path) @@ -301,10 +301,10 @@ class Context(object): def check_package_dir(self, dir, package_names): return Utils.check_package_dir(dir, tuple(package_names)) - def c_file_out_of_date(self, source_path, output_path): - if not os.path.exists(output_path): + def c_file_out_of_date(self, source_path, output_path): + if not os.path.exists(output_path): return 1 - c_time = Utils.modification_time(output_path) + c_time = Utils.modification_time(output_path) if Utils.file_newer_than(source_path, c_time): return 1 pos = [source_path] @@ -362,44 +362,44 @@ class Context(object): # Parse the given source file and return a parse tree. num_errors = Errors.num_errors try: - with Utils.open_source_file(source_filename) as f: + with Utils.open_source_file(source_filename) as f: from . import Parsing s = PyrexScanner(f, source_desc, source_encoding = f.encoding, scope = scope, context = self) tree = Parsing.p_module(s, pxd, full_module_name) - if self.options.formal_grammar: - try: - from ..Parser import ConcreteSyntaxTree - except ImportError: - raise RuntimeError( + if self.options.formal_grammar: + try: + from ..Parser import ConcreteSyntaxTree + except ImportError: + raise RuntimeError( "Formal grammar can only be used with compiled Cython with an available pgen.") - ConcreteSyntaxTree.p_module(source_filename) - except UnicodeDecodeError as e: + ConcreteSyntaxTree.p_module(source_filename) + except UnicodeDecodeError as e: #import traceback #traceback.print_exc() - raise self._report_decode_error(source_desc, e) - - if Errors.num_errors > num_errors: - raise CompileError() - return tree - - def _report_decode_error(self, source_desc, exc): - msg = exc.args[-1] - position = exc.args[2] - encoding = exc.args[0] - - line = 1 - column = idx = 0 - with io.open(source_desc.filename, "r", encoding='iso8859-1', newline='') as f: - for line, data in enumerate(f, 1): - idx += len(data) - if idx >= position: - column = position - (idx - len(data)) + 1 + raise self._report_decode_error(source_desc, e) + + if Errors.num_errors > num_errors: + raise CompileError() + return tree + + def _report_decode_error(self, source_desc, exc): + msg = exc.args[-1] + position = exc.args[2] + encoding = exc.args[0] + + line = 1 + column = idx = 0 + with io.open(source_desc.filename, "r", encoding='iso8859-1', newline='') as f: + for line, data in enumerate(f, 1): + idx += len(data) + if idx >= position: + column = position - (idx - len(data)) + 1 break - return error((source_desc, line, column), - "Decoding error, missing or incorrect coding=<encoding-name> " - "at top of source (cannot decode with encoding %r: %s)" % (encoding, msg)) + return error((source_desc, line, column), + "Decoding error, missing or incorrect coding=<encoding-name> " + "at top of source (cannot decode with encoding %r: %s)" % (encoding, msg)) def extract_module_name(self, path, options): # Find fully_qualified module name from the full pathname @@ -419,9 +419,9 @@ class Context(object): return ".".join(names) def setup_errors(self, options, result): - Errors.reset() # clear any remaining error state + Errors.reset() # clear any remaining error state if options.use_listing_file: - path = result.listing_file = Utils.replace_suffix(result.main_source_file, ".lis") + path = result.listing_file = Utils.replace_suffix(result.main_source_file, ".lis") else: path = None Errors.open_listing_file(path=path, @@ -443,30 +443,30 @@ class Context(object): result.c_file = None -def get_output_filename(source_filename, cwd, options): - if options.cplus: - c_suffix = ".cpp" - else: - c_suffix = ".c" - suggested_file_name = Utils.replace_suffix(source_filename, c_suffix) - if options.output_file: - out_path = os.path.join(cwd, options.output_file) - if os.path.isdir(out_path): - return os.path.join(out_path, os.path.basename(suggested_file_name)) - else: - return out_path - else: - return suggested_file_name - +def get_output_filename(source_filename, cwd, options): + if options.cplus: + c_suffix = ".cpp" + else: + c_suffix = ".c" + suggested_file_name = Utils.replace_suffix(source_filename, c_suffix) + if options.output_file: + out_path = os.path.join(cwd, options.output_file) + if os.path.isdir(out_path): + return os.path.join(out_path, os.path.basename(suggested_file_name)) + else: + return out_path + else: + return suggested_file_name + def create_default_resultobj(compilation_source, options): result = CompilationResult() result.main_source_file = compilation_source.source_desc.filename result.compilation_source = compilation_source source_desc = compilation_source.source_desc - result.c_file = get_output_filename(source_desc.filename, - compilation_source.cwd, options) - result.embedded_metadata = options.embedded_metadata + result.c_file = get_output_filename(source_desc.filename, + compilation_source.cwd, options) + result.embedded_metadata = options.embedded_metadata return result @@ -481,10 +481,10 @@ def run_pipeline(source, options, full_module_name=None, context=None): # Set up source object cwd = os.getcwd() abs_path = os.path.abspath(source) - full_module_name = full_module_name or options.module_name or context.extract_module_name(source, options) + full_module_name = full_module_name or options.module_name or context.extract_module_name(source, options) + + Utils.raise_error_if_module_name_forbidden(full_module_name) - Utils.raise_error_if_module_name_forbidden(full_module_name) - if options.relative_path_in_code_position_comments: rel_path = full_module_name.replace('.', os.sep) + source_ext if not abs_path.endswith(rel_path): @@ -503,9 +503,9 @@ def run_pipeline(source, options, full_module_name=None, context=None): # By default, decide based on whether an html file already exists. html_filename = os.path.splitext(result.c_file)[0] + ".html" if os.path.exists(html_filename): - with io.open(html_filename, "r", encoding="UTF-8") as html_file: - if u'<!-- Generated by Cython' in html_file.read(100): - options.annotate = True + with io.open(html_filename, "r", encoding="UTF-8") as html_file: + if u'<!-- Generated by Cython' in html_file.read(100): + options.annotate = True # Get pipeline if source_ext.lower() == '.py' or not source_ext: @@ -537,10 +537,10 @@ class CompilationSource(object): class CompilationOptions(object): - r""" - See default_options at the end of this module for a list of all possible - options and CmdLine.usage and CmdLine.parse_command_line() for their - meaning. + r""" + See default_options at the end of this module for a list of all possible + options and CmdLine.usage and CmdLine.parse_command_line() for their + meaning. """ def __init__(self, defaults=None, **kw): self.include_path = [] @@ -559,15 +559,15 @@ class CompilationOptions(object): # ignore valid options that are not in the defaults unknown_options.difference_update(['include_path']) if unknown_options: - message = "got unknown compilation option%s, please remove: %s" % ( + message = "got unknown compilation option%s, please remove: %s" % ( 's' if len(unknown_options) > 1 else '', - ', '.join(unknown_options)) + ', '.join(unknown_options)) raise ValueError(message) - directive_defaults = Options.get_directive_defaults() - directives = dict(options['compiler_directives']) # copy mutable field + directive_defaults = Options.get_directive_defaults() + directives = dict(options['compiler_directives']) # copy mutable field # check for invalid directives - unknown_directives = set(directives) - set(directive_defaults) + unknown_directives = set(directives) - set(directive_defaults) if unknown_directives: message = "got unknown compiler directive%s: %s" % ( 's' if len(unknown_directives) > 1 else '', @@ -579,13 +579,13 @@ class CompilationOptions(object): warnings.warn("C++ mode forced when in Pythran mode!") options['cplus'] = True if 'language_level' in directives and 'language_level' not in kw: - options['language_level'] = directives['language_level'] - elif not options.get('language_level'): - options['language_level'] = directive_defaults.get('language_level') - if 'formal_grammar' in directives and 'formal_grammar' not in kw: - options['formal_grammar'] = directives['formal_grammar'] - if options['cache'] is True: - options['cache'] = os.path.join(Utils.get_cython_cache_dir(), 'compiler') + options['language_level'] = directives['language_level'] + elif not options.get('language_level'): + options['language_level'] = directive_defaults.get('language_level') + if 'formal_grammar' in directives and 'formal_grammar' not in kw: + options['formal_grammar'] = directives['formal_grammar'] + if options['cache'] is True: + options['cache'] = os.path.join(Utils.get_cython_cache_dir(), 'compiler') self.__dict__.update(options) @@ -598,84 +598,84 @@ class CompilationOptions(object): return Context(self.include_path, self.compiler_directives, self.cplus, self.language_level, options=self) - def get_fingerprint(self): - r""" - Return a string that contains all the options that are relevant for cache invalidation. - """ - # Collect only the data that can affect the generated file(s). - data = {} - - for key, value in self.__dict__.items(): - if key in ['show_version', 'errors_to_stderr', 'verbose', 'quiet']: - # verbosity flags have no influence on the compilation result - continue - elif key in ['output_file', 'output_dir']: - # ignore the exact name of the output file - continue - elif key in ['timestamps']: - # the cache cares about the content of files, not about the timestamps of sources - continue - elif key in ['cache']: - # hopefully caching has no influence on the compilation result - continue - elif key in ['compiler_directives']: - # directives passed on to the C compiler do not influence the generated C code - continue - elif key in ['include_path']: - # this path changes which headers are tracked as dependencies, - # it has no influence on the generated C code - continue - elif key in ['working_path']: - # this path changes where modules and pxd files are found; - # their content is part of the fingerprint anyway, their - # absolute path does not matter - continue - elif key in ['create_extension']: - # create_extension() has already mangled the options, e.g., - # embedded_metadata, when the fingerprint is computed so we - # ignore it here. - continue - elif key in ['build_dir']: - # the (temporary) directory where we collect dependencies - # has no influence on the C output - continue - elif key in ['use_listing_file', 'generate_pxi', 'annotate', 'annotate_coverage_xml']: - # all output files are contained in the cache so the types of - # files generated must be part of the fingerprint - data[key] = value - elif key in ['formal_grammar', 'evaluate_tree_assertions']: - # these bits can change whether compilation to C passes/fails - data[key] = value - elif key in ['embedded_metadata', 'emit_linenums', 'c_line_in_traceback', 'gdb_debug', 'relative_path_in_code_position_comments']: - # the generated code contains additional bits when these are set - data[key] = value - elif key in ['cplus', 'language_level', 'compile_time_env', 'np_pythran']: - # assorted bits that, e.g., influence the parser - data[key] = value - elif key == ['capi_reexport_cincludes']: - if self.capi_reexport_cincludes: - # our caching implementation does not yet include fingerprints of all the header files - raise NotImplementedError('capi_reexport_cincludes is not compatible with Cython caching') - elif key == ['common_utility_include_dir']: - if self.common_utility_include_dir: - raise NotImplementedError('common_utility_include_dir is not compatible with Cython caching yet') - else: - # any unexpected option should go into the fingerprint; it's better - # to recompile than to return incorrect results from the cache. - data[key] = value - - def to_fingerprint(item): - r""" - Recursively turn item into a string, turning dicts into lists with - deterministic ordering. - """ - if isinstance(item, dict): - item = sorted([(repr(key), to_fingerprint(value)) for key, value in item.items()]) - return repr(item) - - return to_fingerprint(data) - - + def get_fingerprint(self): + r""" + Return a string that contains all the options that are relevant for cache invalidation. + """ + # Collect only the data that can affect the generated file(s). + data = {} + + for key, value in self.__dict__.items(): + if key in ['show_version', 'errors_to_stderr', 'verbose', 'quiet']: + # verbosity flags have no influence on the compilation result + continue + elif key in ['output_file', 'output_dir']: + # ignore the exact name of the output file + continue + elif key in ['timestamps']: + # the cache cares about the content of files, not about the timestamps of sources + continue + elif key in ['cache']: + # hopefully caching has no influence on the compilation result + continue + elif key in ['compiler_directives']: + # directives passed on to the C compiler do not influence the generated C code + continue + elif key in ['include_path']: + # this path changes which headers are tracked as dependencies, + # it has no influence on the generated C code + continue + elif key in ['working_path']: + # this path changes where modules and pxd files are found; + # their content is part of the fingerprint anyway, their + # absolute path does not matter + continue + elif key in ['create_extension']: + # create_extension() has already mangled the options, e.g., + # embedded_metadata, when the fingerprint is computed so we + # ignore it here. + continue + elif key in ['build_dir']: + # the (temporary) directory where we collect dependencies + # has no influence on the C output + continue + elif key in ['use_listing_file', 'generate_pxi', 'annotate', 'annotate_coverage_xml']: + # all output files are contained in the cache so the types of + # files generated must be part of the fingerprint + data[key] = value + elif key in ['formal_grammar', 'evaluate_tree_assertions']: + # these bits can change whether compilation to C passes/fails + data[key] = value + elif key in ['embedded_metadata', 'emit_linenums', 'c_line_in_traceback', 'gdb_debug', 'relative_path_in_code_position_comments']: + # the generated code contains additional bits when these are set + data[key] = value + elif key in ['cplus', 'language_level', 'compile_time_env', 'np_pythran']: + # assorted bits that, e.g., influence the parser + data[key] = value + elif key == ['capi_reexport_cincludes']: + if self.capi_reexport_cincludes: + # our caching implementation does not yet include fingerprints of all the header files + raise NotImplementedError('capi_reexport_cincludes is not compatible with Cython caching') + elif key == ['common_utility_include_dir']: + if self.common_utility_include_dir: + raise NotImplementedError('common_utility_include_dir is not compatible with Cython caching yet') + else: + # any unexpected option should go into the fingerprint; it's better + # to recompile than to return incorrect results from the cache. + data[key] = value + + def to_fingerprint(item): + r""" + Recursively turn item into a string, turning dicts into lists with + deterministic ordering. + """ + if isinstance(item, dict): + item = sorted([(repr(key), to_fingerprint(value)) for key, value in item.items()]) + return repr(item) + + return to_fingerprint(data) + + class CompilationResult(object): """ Results from the Cython compiler: @@ -745,14 +745,14 @@ def compile_multiple(sources, options): timestamps = options.timestamps verbose = options.verbose context = None - cwd = os.getcwd() + cwd = os.getcwd() for source in sources: if source not in processed: if context is None: context = options.create_context() - output_filename = get_output_filename(source, cwd, options) - out_of_date = context.c_file_out_of_date(source, output_filename) - if (not timestamps) or out_of_date: + output_filename = get_output_filename(source, cwd, options) + out_of_date = context.c_file_out_of_date(source, output_filename) + if (not timestamps) or out_of_date: if verbose: sys.stderr.write("Compiling %s\n" % source) @@ -782,71 +782,71 @@ def compile(source, options = None, full_module_name = None, **kwds): return compile_multiple(source, options) -@Utils.cached_function -def search_include_directories(dirs, qualified_name, suffix, pos, include=False): - """ - Search the list of include directories for the given file name. - - If a source file position is given, first searches the directory - containing that file. Returns None if not found, but does not - report an error. - - The 'include' option will disable package dereferencing. - """ - - if pos: - file_desc = pos[0] - if not isinstance(file_desc, FileSourceDescriptor): - raise RuntimeError("Only file sources for code supported") - if include: - dirs = (os.path.dirname(file_desc.filename),) + dirs - else: - dirs = (Utils.find_root_package_dir(file_desc.filename),) + dirs - - dotted_filename = qualified_name - if suffix: - dotted_filename += suffix - - if not include: - names = qualified_name.split('.') - package_names = tuple(names[:-1]) - module_name = names[-1] - module_filename = module_name + suffix - package_filename = "__init__" + suffix - - for dirname in dirs: - path = os.path.join(dirname, dotted_filename) - if os.path.exists(path): - return path - - if not include: - package_dir = Utils.check_package_dir(dirname, package_names) - if package_dir is not None: - path = os.path.join(package_dir, module_filename) - if os.path.exists(path): - return path - path = os.path.join(package_dir, module_name, - package_filename) - if os.path.exists(path): - return path - - # Arcadia-specific lookup: search for packages in include paths, - # ignoring existence of __init__.py files as packages markers - # (they are not required by Arcadia build system) - if not include: - for dir in dirs: - package_dir = os.path.join(dir, *package_names) - path = os.path.join(package_dir, module_filename) - if os.path.exists(path): - return path - path = os.path.join(dir, package_dir, module_name, - package_filename) - if os.path.exists(path): - return path - - return None - - +@Utils.cached_function +def search_include_directories(dirs, qualified_name, suffix, pos, include=False): + """ + Search the list of include directories for the given file name. + + If a source file position is given, first searches the directory + containing that file. Returns None if not found, but does not + report an error. + + The 'include' option will disable package dereferencing. + """ + + if pos: + file_desc = pos[0] + if not isinstance(file_desc, FileSourceDescriptor): + raise RuntimeError("Only file sources for code supported") + if include: + dirs = (os.path.dirname(file_desc.filename),) + dirs + else: + dirs = (Utils.find_root_package_dir(file_desc.filename),) + dirs + + dotted_filename = qualified_name + if suffix: + dotted_filename += suffix + + if not include: + names = qualified_name.split('.') + package_names = tuple(names[:-1]) + module_name = names[-1] + module_filename = module_name + suffix + package_filename = "__init__" + suffix + + for dirname in dirs: + path = os.path.join(dirname, dotted_filename) + if os.path.exists(path): + return path + + if not include: + package_dir = Utils.check_package_dir(dirname, package_names) + if package_dir is not None: + path = os.path.join(package_dir, module_filename) + if os.path.exists(path): + return path + path = os.path.join(package_dir, module_name, + package_filename) + if os.path.exists(path): + return path + + # Arcadia-specific lookup: search for packages in include paths, + # ignoring existence of __init__.py files as packages markers + # (they are not required by Arcadia build system) + if not include: + for dir in dirs: + package_dir = os.path.join(dir, *package_names) + path = os.path.join(package_dir, module_filename) + if os.path.exists(path): + return path + path = os.path.join(dir, package_dir, module_name, + package_filename) + if os.path.exists(path): + return path + + return None + + # ------------------------------------------------------------------------ # # Main command-line entry point @@ -875,7 +875,7 @@ def main(command_line = 0): result = compile(sources, options) if result.num_errors > 0: any_failures = 1 - except (EnvironmentError, PyrexError) as e: + except (EnvironmentError, PyrexError) as e: sys.stderr.write(str(e) + '\n') any_failures = 1 if any_failures: @@ -895,7 +895,7 @@ default_options = dict( cplus = 0, output_file = None, annotate = None, - annotate_coverage_xml = None, + annotate_coverage_xml = None, generate_pxi = 0, capi_reexport_cincludes = 0, working_path = "", @@ -903,21 +903,21 @@ default_options = dict( verbose = 0, quiet = 0, compiler_directives = {}, - embedded_metadata = {}, + embedded_metadata = {}, evaluate_tree_assertions = False, emit_linenums = False, relative_path_in_code_position_comments = True, c_line_in_traceback = True, - language_level = None, # warn but default to 2 - formal_grammar = False, + language_level = None, # warn but default to 2 + formal_grammar = False, gdb_debug = False, - module_name = None, - init_suffix = None, + module_name = None, + init_suffix = None, compile_time_env = None, common_utility_include_dir = None, output_dir=None, build_dir=None, - cache=None, + cache=None, create_extension=None, np_pythran=False ) diff --git a/contrib/tools/cython/Cython/Compiler/MemoryView.py b/contrib/tools/cython/Cython/Compiler/MemoryView.py index 9974bb4db3..0406d6c716 100644 --- a/contrib/tools/cython/Cython/Compiler/MemoryView.py +++ b/contrib/tools/cython/Cython/Compiler/MemoryView.py @@ -25,7 +25,7 @@ ERR_UNINITIALIZED = ("Cannot check if memoryview %s is initialized without the " def concat_flags(*flags): return "(%s)" % "|".join(flags) - + format_flag = "PyBUF_FORMAT" memview_c_contiguous = "(PyBUF_C_CONTIGUOUS | PyBUF_FORMAT)" @@ -67,7 +67,7 @@ memview_typeptr_cname = '__pyx_memoryview_type' memview_objstruct_cname = '__pyx_memoryview_obj' memviewslice_cname = u'__Pyx_memviewslice' - + def put_init_entry(mv_cname, code): code.putln("%s.data = NULL;" % mv_cname) code.putln("%s.memview = NULL;" % mv_cname) @@ -76,7 +76,7 @@ def put_init_entry(mv_cname, code): #def axes_to_str(axes): # return "".join([access[0].upper()+packing[0] for (access, packing) in axes]) - + def put_acquire_memoryviewslice(lhs_cname, lhs_type, lhs_pos, rhs, code, have_gil=False, first_assignment=True): "We can avoid decreffing the lhs if we know it is the first assignment" @@ -97,7 +97,7 @@ def put_acquire_memoryviewslice(lhs_cname, lhs_type, lhs_pos, rhs, code, if not pretty_rhs: code.funcstate.release_temp(rhstmp) - + def put_assign_to_memviewslice(lhs_cname, rhs, rhs_cname, memviewslicetype, code, have_gil=False, first_assignment=False): if not first_assignment: @@ -108,7 +108,7 @@ def put_assign_to_memviewslice(lhs_cname, rhs, rhs_cname, memviewslicetype, code code.putln("%s = %s;" % (lhs_cname, rhs_cname)) - + def get_buf_flags(specs): is_c_contig, is_f_contig = is_cf_contig(specs) @@ -124,13 +124,13 @@ def get_buf_flags(specs): else: return memview_strided_access - + def insert_newaxes(memoryviewtype, n): axes = [('direct', 'strided')] * n axes.extend(memoryviewtype.axes) return PyrexTypes.MemoryViewSliceType(memoryviewtype.dtype, axes) - + def broadcast_types(src, dst): n = abs(src.ndim - dst.ndim) if src.ndim < dst.ndim: @@ -173,20 +173,20 @@ def valid_memslice_dtype(dtype, i=0): class MemoryViewSliceBufferEntry(Buffer.BufferEntry): - """ - May be used during code generation time to be queried for - shape/strides/suboffsets attributes, or to perform indexing or slicing. - """ + """ + May be used during code generation time to be queried for + shape/strides/suboffsets attributes, or to perform indexing or slicing. + """ def __init__(self, entry): self.entry = entry self.type = entry.type self.cname = entry.cname - + self.buf_ptr = "%s.data" % self.cname dtype = self.entry.type.dtype - self.buf_ptr_type = PyrexTypes.CPtrType(dtype) - self.init_attributes() + self.buf_ptr_type = PyrexTypes.CPtrType(dtype) + self.init_attributes() def get_buf_suboffsetvars(self): return self._for_all_ndim("%s.suboffsets[%d]") @@ -203,12 +203,12 @@ class MemoryViewSliceBufferEntry(Buffer.BufferEntry): return self._generate_buffer_lookup_code(code, axes) def _generate_buffer_lookup_code(self, code, axes, cast_result=True): - """ - Generate a single expression that indexes the memory view slice - in each dimension. - """ + """ + Generate a single expression that indexes the memory view slice + in each dimension. + """ bufp = self.buf_ptr - type_decl = self.type.dtype.empty_declaration_code() + type_decl = self.type.dtype.empty_declaration_code() for dim, index, access, packing in axes: shape = "%s.shape[%d]" % (self.cname, dim) @@ -257,9 +257,9 @@ class MemoryViewSliceBufferEntry(Buffer.BufferEntry): then it must be coercible to Py_ssize_t Simply call __pyx_memoryview_slice_memviewslice with the right - arguments, unless the dimension is omitted or a bare ':', in which - case we copy over the shape/strides/suboffsets attributes directly - for that dimension. + arguments, unless the dimension is omitted or a bare ':', in which + case we copy over the shape/strides/suboffsets attributes directly + for that dimension. """ src = self.cname @@ -267,46 +267,46 @@ class MemoryViewSliceBufferEntry(Buffer.BufferEntry): code.putln("%(dst)s.memview = %(src)s.memview;" % locals()) code.put_incref_memoryviewslice(dst) - all_dimensions_direct = all(access == 'direct' for access, packing in self.type.axes) - suboffset_dim_temp = [] - - def get_suboffset_dim(): - # create global temp variable at request - if not suboffset_dim_temp: - suboffset_dim = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False) - code.putln("%s = -1;" % suboffset_dim) - suboffset_dim_temp.append(suboffset_dim) - return suboffset_dim_temp[0] - + all_dimensions_direct = all(access == 'direct' for access, packing in self.type.axes) + suboffset_dim_temp = [] + + def get_suboffset_dim(): + # create global temp variable at request + if not suboffset_dim_temp: + suboffset_dim = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False) + code.putln("%s = -1;" % suboffset_dim) + suboffset_dim_temp.append(suboffset_dim) + return suboffset_dim_temp[0] + dim = -1 - new_ndim = 0 + new_ndim = 0 for index in indices: - if index.is_none: - # newaxis - for attrib, value in [('shape', 1), ('strides', 0), ('suboffsets', -1)]: - code.putln("%s.%s[%d] = %d;" % (dst, attrib, new_ndim, value)) - - new_ndim += 1 - continue - - dim += 1 - access, packing = self.type.axes[dim] + if index.is_none: + # newaxis + for attrib, value in [('shape', 1), ('strides', 0), ('suboffsets', -1)]: + code.putln("%s.%s[%d] = %d;" % (dst, attrib, new_ndim, value)) + + new_ndim += 1 + continue + + dim += 1 + access, packing = self.type.axes[dim] if isinstance(index, ExprNodes.SliceNode): # slice, unspecified dimension, or part of ellipsis - d = dict(locals()) + d = dict(locals()) for s in "start stop step".split(): idx = getattr(index, s) have_idx = d['have_' + s] = not idx.is_none - d[s] = idx.result() if have_idx else "0" + d[s] = idx.result() if have_idx else "0" - if not (d['have_start'] or d['have_stop'] or d['have_step']): + if not (d['have_start'] or d['have_stop'] or d['have_step']): # full slice (:), simply copy over the extent, stride # and suboffset. Also update suboffset_dim if needed d['access'] = access - util_name = "SimpleSlice" + util_name = "SimpleSlice" else: - util_name = "ToughSlice" + util_name = "ToughSlice" d['error_goto'] = code.error_goto(index.pos) new_ndim += 1 @@ -314,42 +314,42 @@ class MemoryViewSliceBufferEntry(Buffer.BufferEntry): # normal index idx = index.result() - indirect = access != 'direct' - if indirect: - generic = access == 'full' + indirect = access != 'direct' + if indirect: + generic = access == 'full' if new_ndim != 0: return error(index.pos, "All preceding dimensions must be " "indexed and not sliced") - d = dict( - locals(), - wraparound=int(directives['wraparound']), + d = dict( + locals(), + wraparound=int(directives['wraparound']), boundscheck=int(directives['boundscheck']), - ) + ) if d['boundscheck']: d['error_goto'] = code.error_goto(index.pos) - util_name = "SliceIndex" + util_name = "SliceIndex" + + _, impl = TempitaUtilityCode.load_as_string(util_name, "MemoryView_C.c", context=d) + code.put(impl) - _, impl = TempitaUtilityCode.load_as_string(util_name, "MemoryView_C.c", context=d) - code.put(impl) + if suboffset_dim_temp: + code.funcstate.release_temp(suboffset_dim_temp[0]) - if suboffset_dim_temp: - code.funcstate.release_temp(suboffset_dim_temp[0]) - def empty_slice(pos): none = ExprNodes.NoneNode(pos) return ExprNodes.SliceNode(pos, start=none, stop=none, step=none) - -def unellipsify(indices, ndim): + +def unellipsify(indices, ndim): result = [] seen_ellipsis = False have_slices = False - newaxes = [newaxis for newaxis in indices if newaxis.is_none] + newaxes = [newaxis for newaxis in indices if newaxis.is_none] n_indices = len(indices) - len(newaxes) for index in indices: @@ -364,7 +364,7 @@ def unellipsify(indices, ndim): result.extend([full_slice] * nslices) seen_ellipsis = True else: - have_slices = have_slices or index.is_slice or index.is_none + have_slices = have_slices or index.is_slice or index.is_none result.append(index) result_length = len(result) - len(newaxes) @@ -373,9 +373,9 @@ def unellipsify(indices, ndim): nslices = ndim - result_length result.extend([empty_slice(indices[-1].pos)] * nslices) - return have_slices, result, newaxes + return have_slices, result, newaxes + - def get_memoryview_flag(access, packing): if access == 'full' and packing in ('strided', 'follow'): return 'generic' @@ -391,47 +391,47 @@ def get_memoryview_flag(access, packing): assert (access, packing) == ('direct', 'contig'), (access, packing) return 'contiguous' - + def get_is_contig_func_name(contig_type, ndim): assert contig_type in ('C', 'F') return "__pyx_memviewslice_is_contig_%s%d" % (contig_type, ndim) - + def get_is_contig_utility(contig_type, ndim): assert contig_type in ('C', 'F') C = dict(context, ndim=ndim, contig_type=contig_type) utility = load_memview_c_utility("MemviewSliceCheckContig", C, requires=[is_contig_utility]) return utility - -def slice_iter(slice_type, slice_result, ndim, code): - if slice_type.is_c_contig or slice_type.is_f_contig: - return ContigSliceIter(slice_type, slice_result, ndim, code) + +def slice_iter(slice_type, slice_result, ndim, code): + if slice_type.is_c_contig or slice_type.is_f_contig: + return ContigSliceIter(slice_type, slice_result, ndim, code) else: - return StridedSliceIter(slice_type, slice_result, ndim, code) + return StridedSliceIter(slice_type, slice_result, ndim, code) class SliceIter(object): - def __init__(self, slice_type, slice_result, ndim, code): + def __init__(self, slice_type, slice_result, ndim, code): self.slice_type = slice_type - self.slice_result = slice_result + self.slice_result = slice_result self.code = code self.ndim = ndim - + class ContigSliceIter(SliceIter): def start_loops(self): code = self.code code.begin_block() - type_decl = self.slice_type.dtype.empty_declaration_code() + type_decl = self.slice_type.dtype.empty_declaration_code() - total_size = ' * '.join("%s.shape[%d]" % (self.slice_result, i) - for i in range(self.ndim)) + total_size = ' * '.join("%s.shape[%d]" % (self.slice_result, i) + for i in range(self.ndim)) code.putln("Py_ssize_t __pyx_temp_extent = %s;" % total_size) code.putln("Py_ssize_t __pyx_temp_idx;") code.putln("%s *__pyx_temp_pointer = (%s *) %s.data;" % ( - type_decl, type_decl, self.slice_result)) + type_decl, type_decl, self.slice_result)) code.putln("for (__pyx_temp_idx = 0; " "__pyx_temp_idx < __pyx_temp_extent; " "__pyx_temp_idx++) {") @@ -443,20 +443,20 @@ class ContigSliceIter(SliceIter): self.code.putln("}") self.code.end_block() - + class StridedSliceIter(SliceIter): def start_loops(self): code = self.code code.begin_block() for i in range(self.ndim): - t = i, self.slice_result, i + t = i, self.slice_result, i code.putln("Py_ssize_t __pyx_temp_extent_%d = %s.shape[%d];" % t) code.putln("Py_ssize_t __pyx_temp_stride_%d = %s.strides[%d];" % t) code.putln("char *__pyx_temp_pointer_%d;" % i) code.putln("Py_ssize_t __pyx_temp_idx_%d;" % i) - code.putln("__pyx_temp_pointer_0 = %s.data;" % self.slice_result) + code.putln("__pyx_temp_pointer_0 = %s.data;" % self.slice_result) for i in range(self.ndim): if i > 0: @@ -486,23 +486,23 @@ def copy_c_or_fortran_cname(memview): return "__pyx_memoryview_copy_slice_%s_%s" % ( memview.specialization_suffix(), c_or_f) - + def get_copy_new_utility(pos, from_memview, to_memview): - if (from_memview.dtype != to_memview.dtype and - not (from_memview.dtype.is_const and from_memview.dtype.const_base_type == to_memview.dtype)): - error(pos, "dtypes must be the same!") - return + if (from_memview.dtype != to_memview.dtype and + not (from_memview.dtype.is_const and from_memview.dtype.const_base_type == to_memview.dtype)): + error(pos, "dtypes must be the same!") + return if len(from_memview.axes) != len(to_memview.axes): - error(pos, "number of dimensions must be same") - return + error(pos, "number of dimensions must be same") + return if not (to_memview.is_c_contig or to_memview.is_f_contig): - error(pos, "to_memview must be c or f contiguous.") - return + error(pos, "to_memview must be c or f contiguous.") + return for (access, packing) in from_memview.axes: if access != 'direct': - error(pos, "cannot handle 'full' or 'ptr' access at this time.") - return + error(pos, "cannot handle 'full' or 'ptr' access at this time.") + return if to_memview.is_c_contig: mode = 'c' @@ -516,14 +516,14 @@ def get_copy_new_utility(pos, from_memview, to_memview): context=dict( context, mode=mode, - dtype_decl=to_memview.dtype.empty_declaration_code(), + dtype_decl=to_memview.dtype.empty_declaration_code(), contig_flag=contig_flag, ndim=to_memview.ndim, func_cname=copy_c_or_fortran_cname(to_memview), dtype_is_object=int(to_memview.dtype.is_pyobject)), requires=[copy_contents_new_utility]) - + def get_axes_specs(env, axes): ''' get_axes_specs(env, axes) -> list of (access, packing) specs for each axis. @@ -569,7 +569,7 @@ def get_axes_specs(env, axes): if entry.name in view_constant_to_access_packing: axes_specs.append(view_constant_to_access_packing[entry.name]) else: - raise CompileError(axis.step.pos, INVALID_ERR) + raise CompileError(axis.step.pos, INVALID_ERR) else: raise CompileError(axis.step.pos, INVALID_ERR) @@ -704,7 +704,7 @@ def validate_axes_specs(positions, specs, is_c_contig, is_f_contig): if access == 'ptr': last_indirect_dimension = idx - for idx, (pos, (access, packing)) in enumerate(zip(positions, specs)): + for idx, (pos, (access, packing)) in enumerate(zip(positions, specs)): if not (access in access_specs and packing in packing_specs): diff --git a/contrib/tools/cython/Cython/Compiler/ModuleNode.py b/contrib/tools/cython/Cython/Compiler/ModuleNode.py index 0eb4a02ab3..cd7166408e 100644 --- a/contrib/tools/cython/Cython/Compiler/ModuleNode.py +++ b/contrib/tools/cython/Cython/Compiler/ModuleNode.py @@ -9,12 +9,12 @@ cython.declare(Naming=object, Options=object, PyrexTypes=object, TypeSlots=objec error=object, warning=object, py_object_type=object, UtilityCode=object, EncodedString=object, re=object) -from collections import defaultdict -import json -import operator +from collections import defaultdict +import json +import operator import os import re - + from .PyrexTypes import CPtrType from . import Future from . import Annotate @@ -28,7 +28,7 @@ from . import Pythran from .Errors import error, warning from .PyrexTypes import py_object_type -from ..Utils import open_new_file, replace_suffix, decode_filename, build_hex_version +from ..Utils import open_new_file, replace_suffix, decode_filename, build_hex_version from .Code import UtilityCode, IncludeCode from .StringEncoding import EncodedString from .Pythran import has_np_pythran @@ -37,25 +37,25 @@ def check_c_declarations_pxd(module_node): module_node.scope.check_c_classes_pxd() return module_node - + def check_c_declarations(module_node): module_node.scope.check_c_classes() module_node.scope.check_c_functions() return module_node - -def generate_c_code_config(env, options): - if Options.annotate or options.annotate: - emit_linenums = False - else: - emit_linenums = options.emit_linenums - - return Code.CCodeConfig( - emit_linenums=emit_linenums, - emit_code_comments=env.directives['emit_code_comments'], - c_line_in_traceback=options.c_line_in_traceback) - - + +def generate_c_code_config(env, options): + if Options.annotate or options.annotate: + emit_linenums = False + else: + emit_linenums = options.emit_linenums + + return Code.CCodeConfig( + emit_linenums=emit_linenums, + emit_code_comments=env.directives['emit_code_comments'], + c_line_in_traceback=options.c_line_in_traceback) + + class ModuleNode(Nodes.Node, Nodes.BlockNode): # doc string or None # body StatListNode @@ -108,13 +108,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): def analyse_declarations(self, env): if has_np_pythran(env): Pythran.include_pythran_generic(env) - if self.directives: - env.old_style_globals = self.directives['old_style_globals'] + if self.directives: + env.old_style_globals = self.directives['old_style_globals'] if not Options.docstrings: env.doc = self.doc = None elif Options.embed_pos_in_docstring: env.doc = EncodedString(u'File: %s (starting at line %s)' % Nodes.relative_position(self.pos)) - if self.doc is not None: + if self.doc is not None: env.doc = EncodedString(env.doc + u'\n' + self.doc) env.doc.encoding = self.doc.encoding else: @@ -123,17 +123,17 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): self.body.analyse_declarations(env) - def prepare_utility_code(self): - # prepare any utility code that must be created before code generation - # specifically: CythonUtilityCode - env = self.scope - if env.has_import_star: - self.create_import_star_conversion_utility_code(env) - for name, entry in sorted(env.entries.items()): - if (entry.create_wrapper and entry.scope is env - and entry.is_type and entry.type.is_enum): - entry.type.create_type_wrapper(env) - + def prepare_utility_code(self): + # prepare any utility code that must be created before code generation + # specifically: CythonUtilityCode + env = self.scope + if env.has_import_star: + self.create_import_star_conversion_utility_code(env) + for name, entry in sorted(env.entries.items()): + if (entry.create_wrapper and entry.scope is env + and entry.is_type and entry.type.is_enum): + entry.type.create_type_wrapper(env) + def process_implementation(self, options, result): env = self.scope env.return_type = PyrexTypes.c_void_type @@ -142,7 +142,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): self.sort_cdef_classes(env) self.generate_c_code(env, options, result) self.generate_h_code(env, options, result) - self.generate_api_code(env, options, result) + self.generate_api_code(env, options, result) def has_imported_c_functions(self): for module in self.referenced_modules: @@ -161,18 +161,18 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): h_vars = h_entries(env.var_entries) h_funcs = h_entries(env.cfunc_entries) h_extension_types = h_entries(env.c_class_entries) - if h_types or h_vars or h_funcs or h_extension_types: + if h_types or h_vars or h_funcs or h_extension_types: result.h_file = replace_suffix(result.c_file, ".h") h_code = Code.CCodeWriter() - c_code_config = generate_c_code_config(env, options) - Code.GlobalState(h_code, self, c_code_config) + c_code_config = generate_c_code_config(env, options) + Code.GlobalState(h_code, self, c_code_config) if options.generate_pxi: result.i_file = replace_suffix(result.c_file, ".pxi") i_code = Code.PyrexCodeWriter(result.i_file) else: i_code = None - h_code.put_generated_by() + h_code.put_generated_by() h_guard = Naming.h_guard_prefix + self.api_name(env) h_code.put_h_guard(h_guard) h_code.putln("") @@ -185,8 +185,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): h_code.putln("#ifndef %s" % api_guard) h_code.putln("") self.generate_extern_c_macro_definition(h_code) - h_code.putln("") - self.generate_dl_import_macro(h_code) + h_code.putln("") + self.generate_dl_import_macro(h_code) if h_extension_types: h_code.putln("") for entry in h_extension_types: @@ -208,8 +208,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): h_code.putln("/* It now returns a PyModuleDef instance instead of a PyModule instance. */") h_code.putln("") h_code.putln("#if PY_MAJOR_VERSION < 3") - init_name = 'init' + (options.init_suffix or env.module_name) - h_code.putln("PyMODINIT_FUNC %s(void);" % init_name) + init_name = 'init' + (options.init_suffix or env.module_name) + h_code.putln("PyMODINIT_FUNC %s(void);" % init_name) h_code.putln("#else") h_code.putln("PyMODINIT_FUNC %s(void);" % self.mod_init_func_cname('PyInit', env, options)) h_code.putln("#endif") @@ -227,13 +227,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): Naming.extern_c_macro, entry.type.declaration_code(entry.cname))) if i_code: - i_code.putln("cdef extern %s" % ( - entry.type.declaration_code(entry.cname, pyrex=1))) + i_code.putln("cdef extern %s" % ( + entry.type.declaration_code(entry.cname, pyrex=1))) def api_name(self, env): return env.qualified_name.replace(".", "__") - def generate_api_code(self, env, options, result): + def generate_api_code(self, env, options, result): def api_entries(entries, pxd=0): return [entry for entry in entries if entry.api or (pxd and entry.defined_in_pxd)] @@ -243,16 +243,16 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): if api_vars or api_funcs or api_extension_types: result.api_file = replace_suffix(result.c_file, "_api.h") h_code = Code.CCodeWriter() - c_code_config = generate_c_code_config(env, options) - Code.GlobalState(h_code, self, c_code_config) - h_code.put_generated_by() + c_code_config = generate_c_code_config(env, options) + Code.GlobalState(h_code, self, c_code_config) + h_code.put_generated_by() api_guard = Naming.api_guard_prefix + self.api_name(env) h_code.put_h_guard(api_guard) - # Work around https://bugs.python.org/issue4709 - h_code.putln('#ifdef __MINGW64__') - h_code.putln('#define MS_WIN64') - h_code.putln('#endif') - + # Work around https://bugs.python.org/issue4709 + h_code.putln('#ifdef __MINGW64__') + h_code.putln('#define MS_WIN64') + h_code.putln('#endif') + h_code.putln('#include "Python.h"') if result.h_file: h_code.putln('#include "%s"' % os.path.basename(result.h_file)) @@ -267,14 +267,14 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): h_code.putln("") for entry in api_funcs: type = CPtrType(entry.type) - cname = env.mangle(Naming.func_prefix_api, entry.name) + cname = env.mangle(Naming.func_prefix_api, entry.name) h_code.putln("static %s = 0;" % type.declaration_code(cname)) h_code.putln("#define %s %s" % (entry.name, cname)) if api_vars: h_code.putln("") for entry in api_vars: type = CPtrType(entry.type) - cname = env.mangle(Naming.varptr_prefix_api, entry.name) + cname = env.mangle(Naming.varptr_prefix_api, entry.name) h_code.putln("static %s = 0;" % type.declaration_code(cname)) h_code.putln("#define %s (*%s)" % (entry.name, cname)) h_code.put(UtilityCode.load_as_string("PyIdentifierFromString", "ImportExport.c")[0]) @@ -283,28 +283,28 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): if api_funcs: h_code.put(UtilityCode.load_as_string("FunctionImport", "ImportExport.c")[1]) if api_extension_types: - h_code.put(UtilityCode.load_as_string("TypeImport", "ImportExport.c")[0]) + h_code.put(UtilityCode.load_as_string("TypeImport", "ImportExport.c")[0]) h_code.put(UtilityCode.load_as_string("TypeImport", "ImportExport.c")[1]) h_code.putln("") h_code.putln("static int import_%s(void) {" % self.api_name(env)) h_code.putln("PyObject *module = 0;") - h_code.putln('module = PyImport_ImportModule("%s");' % env.qualified_name) + h_code.putln('module = PyImport_ImportModule("%s");' % env.qualified_name) h_code.putln("if (!module) goto bad;") for entry in api_funcs: - cname = env.mangle(Naming.func_prefix_api, entry.name) + cname = env.mangle(Naming.func_prefix_api, entry.name) sig = entry.type.signature_string() h_code.putln( 'if (__Pyx_ImportFunction(module, "%s", (void (**)(void))&%s, "%s") < 0) goto bad;' % (entry.name, cname, sig)) for entry in api_vars: - cname = env.mangle(Naming.varptr_prefix_api, entry.name) - sig = entry.type.empty_declaration_code() + cname = env.mangle(Naming.varptr_prefix_api, entry.name) + sig = entry.type.empty_declaration_code() h_code.putln( 'if (__Pyx_ImportVoidPtr(module, "%s", (void **)&%s, "%s") < 0) goto bad;' % (entry.name, cname, sig)) - with ModuleImportGenerator(h_code, imported_modules={env.qualified_name: 'module'}) as import_generator: - for entry in api_extension_types: - self.generate_type_import_call(entry.type, h_code, import_generator, error_code="goto bad;") + with ModuleImportGenerator(h_code, imported_modules={env.qualified_name: 'module'}) as import_generator: + for entry in api_extension_types: + self.generate_type_import_call(entry.type, h_code, import_generator, error_code="goto bad;") h_code.putln("Py_DECREF(module); module = 0;") h_code.putln("return 0;") h_code.putln("bad:") @@ -333,8 +333,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): var_entries = type.scope.var_entries if var_entries: for entry in var_entries: - i_code.putln("cdef %s" % ( - entry.type.declaration_code(entry.cname, pyrex=1))) + i_code.putln("cdef %s" % ( + entry.type.declaration_code(entry.cname, pyrex=1))) else: i_code.putln("pass") i_code.dedent() @@ -345,19 +345,19 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): if Options.annotate or options.annotate: rootwriter = Annotate.AnnotationCCodeWriter() else: - rootwriter = Code.CCodeWriter() - - c_code_config = generate_c_code_config(env, options) - - globalstate = Code.GlobalState( - rootwriter, self, - code_config=c_code_config, - common_utility_include_dir=options.common_utility_include_dir, - ) + rootwriter = Code.CCodeWriter() + + c_code_config = generate_c_code_config(env, options) + + globalstate = Code.GlobalState( + rootwriter, self, + code_config=c_code_config, + common_utility_include_dir=options.common_utility_include_dir, + ) globalstate.initialize_main_c_code() h_code = globalstate['h_code'] - self.generate_module_preamble(env, options, modules, result.embedded_metadata, h_code) + self.generate_module_preamble(env, options, modules, result.embedded_metadata, h_code) globalstate.module_pos = self.pos globalstate.directives = self.directives @@ -382,21 +382,21 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): self.generate_lambda_definitions(env, code) # generate normal variable and function definitions self.generate_variable_definitions(env, code) - + self.body.generate_function_definitions(env, code) - + code.mark_pos(None) self.generate_typeobj_definitions(env, code) self.generate_method_table(env, code) if env.has_import_star: self.generate_import_star(env, code) - self.generate_pymoduledef_struct(env, options, code) + self.generate_pymoduledef_struct(env, options, code) + + # initialise the macro to reduce the code size of one-time functionality + code.putln(UtilityCode.load_as_string("SmallCodeConfig", "ModuleSetupCode.c")[0].strip()) - # initialise the macro to reduce the code size of one-time functionality - code.putln(UtilityCode.load_as_string("SmallCodeConfig", "ModuleSetupCode.c")[0].strip()) - # init_globals is inserted before this - self.generate_module_init_func(modules[:-1], env, options, globalstate['init_module']) + self.generate_module_init_func(modules[:-1], env, options, globalstate['init_module']) self.generate_module_cleanup_func(env, globalstate['cleanup_module']) if Options.embed: self.generate_main_method(env, globalstate['main_method']) @@ -418,29 +418,29 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): if options.gdb_debug: self._serialize_lineno_map(env, rootwriter) if Options.annotate or options.annotate: - self._generate_annotations(rootwriter, result, options) + self._generate_annotations(rootwriter, result, options) - def _generate_annotations(self, rootwriter, result, options): + def _generate_annotations(self, rootwriter, result, options): self.annotate(rootwriter) - coverage_xml_filename = Options.annotate_coverage_xml or options.annotate_coverage_xml - if coverage_xml_filename and os.path.exists(coverage_xml_filename): - try: - import xml.etree.cElementTree as ET - except ImportError: - import xml.etree.ElementTree as ET - coverage_xml = ET.parse(coverage_xml_filename).getroot() + coverage_xml_filename = Options.annotate_coverage_xml or options.annotate_coverage_xml + if coverage_xml_filename and os.path.exists(coverage_xml_filename): + try: + import xml.etree.cElementTree as ET + except ImportError: + import xml.etree.ElementTree as ET + coverage_xml = ET.parse(coverage_xml_filename).getroot() if hasattr(coverage_xml, 'iter'): iterator = coverage_xml.iter() # Python 2.7 & 3.2+ else: iterator = coverage_xml.getiterator() for el in iterator: - el.tail = None # save some memory - else: - coverage_xml = None - - rootwriter.save_annotation(result.main_source_file, result.c_file, coverage_xml=coverage_xml) - + el.tail = None # save some memory + else: + coverage_xml = None + + rootwriter.save_annotation(result.main_source_file, result.c_file, coverage_xml=coverage_xml) + # if we included files, additionally generate one annotation file for each if not self.scope.included_files: return @@ -459,28 +459,28 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): if target_file_dir != target_dir and not os.path.exists(target_file_dir): try: os.makedirs(target_file_dir) - except OSError as e: + except OSError as e: import errno if e.errno != errno.EEXIST: raise - rootwriter.save_annotation(source_file, target_file, coverage_xml=coverage_xml) + rootwriter.save_annotation(source_file, target_file, coverage_xml=coverage_xml) def _serialize_lineno_map(self, env, ccodewriter): tb = env.context.gdb_debug_outputwriter markers = ccodewriter.buffer.allmarkers() - d = defaultdict(list) + d = defaultdict(list) for c_lineno, cython_lineno in enumerate(markers): if cython_lineno > 0: - d[cython_lineno].append(c_lineno + 1) + d[cython_lineno].append(c_lineno + 1) tb.start('LineNumberMapping') - for cython_lineno, c_linenos in sorted(d.items()): - tb.add_entry( - 'LineNumber', - c_linenos=' '.join(map(str, c_linenos)), - cython_lineno=str(cython_lineno), - ) + for cython_lineno, c_linenos in sorted(d.items()): + tb.add_entry( + 'LineNumber', + c_linenos=' '.join(map(str, c_linenos)), + cython_lineno=str(cython_lineno), + ) tb.end('LineNumberMapping') tb.serialize() @@ -625,16 +625,16 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): self.generate_cvariable_declarations(module, modulecode, defined_here) self.generate_cfunction_declarations(module, modulecode, defined_here) - def _put_setup_code(self, code, name): - code.put(UtilityCode.load_as_string(name, "ModuleSetupCode.c")[1]) - - def generate_module_preamble(self, env, options, cimported_modules, metadata, code): - code.put_generated_by() - if metadata: - code.putln("/* BEGIN: Cython Metadata") - code.putln(json.dumps(metadata, indent=4, sort_keys=True)) - code.putln("END: Cython Metadata */") - code.putln("") + def _put_setup_code(self, code, name): + code.put(UtilityCode.load_as_string(name, "ModuleSetupCode.c")[1]) + + def generate_module_preamble(self, env, options, cimported_modules, metadata, code): + code.put_generated_by() + if metadata: + code.putln("/* BEGIN: Cython Metadata") + code.putln(json.dumps(metadata, indent=4, sort_keys=True)) + code.putln("END: Cython Metadata */") + code.putln("") code.putln("#ifndef PY_SSIZE_T_CLEAN") code.putln("#define PY_SSIZE_T_CLEAN") @@ -644,9 +644,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): if inc.location == inc.INITIAL: inc.write(code) code.putln("#ifndef Py_PYTHON_H") - code.putln(" #error Python headers needed to compile C extensions, " - "please install development version of Python.") - code.putln("#elif PY_VERSION_HEX < 0x02060000 || " + code.putln(" #error Python headers needed to compile C extensions, " + "please install development version of Python.") + code.putln("#elif PY_VERSION_HEX < 0x02060000 || " "(0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000)") code.putln(" #error Cython requires Python 2.6+ or Python 3.3+.") code.putln("#else") @@ -654,23 +654,23 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): from .. import __version__ code.putln('#define CYTHON_ABI "%s"' % __version__.replace('.', '_')) - code.putln('#define CYTHON_HEX_VERSION %s' % build_hex_version(__version__)) + code.putln('#define CYTHON_HEX_VERSION %s' % build_hex_version(__version__)) code.putln("#define CYTHON_FUTURE_DIVISION %d" % ( Future.division in env.context.future_directives)) - self._put_setup_code(code, "CModulePreamble") - if env.context.options.cplus: - self._put_setup_code(code, "CppInitCode") - else: - self._put_setup_code(code, "CInitCode") + self._put_setup_code(code, "CModulePreamble") + if env.context.options.cplus: + self._put_setup_code(code, "CppInitCode") + else: + self._put_setup_code(code, "CInitCode") self._put_setup_code(code, "PythonCompatibility") - self._put_setup_code(code, "MathInitCode") + self._put_setup_code(code, "MathInitCode") # Using "(void)cname" to prevent "unused" warnings. - if options.c_line_in_traceback: + if options.c_line_in_traceback: cinfo = "%s = %s; (void)%s; " % (Naming.clineno_cname, Naming.line_c_macro, Naming.clineno_cname) - else: - cinfo = "" + else: + cinfo = "" code.putln("#define __PYX_MARK_ERR_POS(f_index, lineno) \\") code.putln(" { %s = %s[f_index]; (void)%s; %s = lineno; (void)%s; %s}" % ( Naming.filename_cname, Naming.filetable_cname, Naming.filename_cname, @@ -679,7 +679,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): )) code.putln("#define __PYX_ERR(f_index, lineno, Ln_error) \\") code.putln(" { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; }") - + code.putln("") self.generate_extern_c_macro_definition(code) code.putln("") @@ -707,13 +707,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): if c_string_type not in ('bytes', 'bytearray') and not c_string_encoding: error(self.pos, "a default encoding must be provided if c_string_type is not a byte type") code.putln('#define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII %s' % int(c_string_encoding == 'ascii')) - code.putln('#define __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 %s' % - int(c_string_encoding.replace('-', '').lower() == 'utf8')) + code.putln('#define __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 %s' % + int(c_string_encoding.replace('-', '').lower() == 'utf8')) if c_string_encoding == 'default': code.putln('#define __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT 1') else: - code.putln('#define __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT ' - '(PY_MAJOR_VERSION >= 3 && __PYX_DEFAULT_STRING_ENCODING_IS_UTF8)') + code.putln('#define __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT ' + '(PY_MAJOR_VERSION >= 3 && __PYX_DEFAULT_STRING_ENCODING_IS_UTF8)') code.putln('#define __PYX_DEFAULT_STRING_ENCODING "%s"' % c_string_encoding) if c_string_type == 'bytearray': c_string_func_name = 'ByteArray' @@ -734,10 +734,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln('static PyObject *%s = NULL;' % env.module_cname) code.putln('static PyObject *%s;' % env.module_dict_cname) code.putln('static PyObject *%s;' % Naming.builtins_cname) - code.putln('static PyObject *%s = NULL;' % Naming.cython_runtime_cname) + code.putln('static PyObject *%s = NULL;' % Naming.cython_runtime_cname) code.putln('static PyObject *%s;' % Naming.empty_tuple) code.putln('static PyObject *%s;' % Naming.empty_bytes) - code.putln('static PyObject *%s;' % Naming.empty_unicode) + code.putln('static PyObject *%s;' % Naming.empty_unicode) if Options.pre_import is not None: code.putln('static PyObject *%s;' % Naming.preimport_cname) code.putln('static int %s;' % Naming.lineno_cname) @@ -759,11 +759,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln(" #endif") code.putln("#endif") - def generate_dl_import_macro(self, code): - code.putln("#ifndef DL_IMPORT") - code.putln(" #define DL_IMPORT(_T) _T") - code.putln("#endif") - + def generate_dl_import_macro(self, code): + code.putln("#ifndef DL_IMPORT") + code.putln(" #define DL_IMPORT(_T) _T") + code.putln("#endif") + def generate_includes(self, env, cimported_modules, code, early=True, late=True): includes = [] for inc in sorted(env.c_includes.values(), key=IncludeCode.sortkey): @@ -810,8 +810,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): pass elif type.is_struct_or_union or type.is_cpp_class: self.generate_struct_union_predeclaration(entry, code) - elif type.is_ctuple and entry.used: - self.generate_struct_union_predeclaration(entry.type.struct_entry, code) + elif type.is_ctuple and entry.used: + self.generate_struct_union_predeclaration(entry.type.struct_entry, code) elif type.is_extension_type: self.generate_objstruct_predeclaration(type, code) # Actual declarations @@ -825,8 +825,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): self.generate_enum_definition(entry, code) elif type.is_struct_or_union: self.generate_struct_union_definition(entry, code) - elif type.is_ctuple and entry.used: - self.generate_struct_union_definition(entry.type.struct_entry, code) + elif type.is_ctuple and entry.used: + self.generate_struct_union_definition(entry.type.struct_entry, code) elif type.is_cpp_class: self.generate_cpp_class_definition(entry, code) elif type.is_extension_type: @@ -869,8 +869,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): def generate_struct_union_predeclaration(self, entry, code): type = entry.type if type.is_cpp_class and type.templates: - code.putln("template <typename %s>" % ", typename ".join( - [T.empty_declaration_code() for T in type.templates])) + code.putln("template <typename %s>" % ", typename ".join( + [T.empty_declaration_code() for T in type.templates])) code.putln(self.sue_predeclaration(type, type.kind, type.cname)) def sue_header_footer(self, type, kind, name): @@ -899,10 +899,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln(header) var_entries = scope.var_entries if not var_entries: - error(entry.pos, "Empty struct or union definition not allowed outside a 'cdef extern from' block") + error(entry.pos, "Empty struct or union definition not allowed outside a 'cdef extern from' block") for attr in var_entries: code.putln( - "%s;" % attr.type.declaration_code(attr.cname)) + "%s;" % attr.type.declaration_code(attr.cname)) code.putln(footer) if packed: code.putln("#if defined(__SUNPRO_C)") @@ -917,13 +917,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): scope = type.scope if scope: if type.templates: - code.putln("template <class %s>" % ", class ".join( - [T.empty_declaration_code() for T in type.templates])) + code.putln("template <class %s>" % ", class ".join( + [T.empty_declaration_code() for T in type.templates])) # Just let everything be public. code.put("struct %s" % type.cname) if type.base_classes: base_class_decl = ", public ".join( - [base_class.empty_declaration_code() for base_class in type.base_classes]) + [base_class.empty_declaration_code() for base_class in type.base_classes]) code.put(" : public %s" % base_class_decl) code.putln(" {") py_attrs = [e for e in scope.entries.values() @@ -932,8 +932,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): constructor = None destructor = None for attr in scope.var_entries: - if attr.type.is_cfunction: - code.put("inline ") + if attr.type.is_cfunction: + code.put("inline ") if attr.type.is_cfunction and attr.type.is_static_method: code.put("static ") elif attr.name == "<init>": @@ -943,7 +943,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): elif attr.type.is_cfunction: code.put("virtual ") has_virtual_methods = True - code.putln("%s;" % attr.type.declaration_code(attr.cname)) + code.putln("%s;" % attr.type.declaration_code(attr.cname)) is_implementing = 'init_module' in code.globalstate.parts if constructor or py_attrs: if constructor: @@ -1022,11 +1022,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.mark_pos(entry.pos) type = entry.type name = entry.cname or entry.name or "" - header, footer = self.sue_header_footer(type, "enum", name) + header, footer = self.sue_header_footer(type, "enum", name) code.putln(header) enum_values = entry.enum_values if not enum_values: - error(entry.pos, "Empty enum definition not allowed outside a 'cdef extern from' block") + error(entry.pos, "Empty enum definition not allowed outside a 'cdef extern from' block") else: last_entry = enum_values[-1] # this does not really generate code, just builds the result value @@ -1080,15 +1080,15 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): if type.vtabstruct_cname: code.putln("") - code.putln("struct %s {" % type.vtabstruct_cname) + code.putln("struct %s {" % type.vtabstruct_cname) if type.base_type and type.base_type.vtabstruct_cname: code.putln("struct %s %s;" % ( type.base_type.vtabstruct_cname, Naming.obj_base_cname)) for method_entry in scope.cfunc_entries: if not method_entry.is_inherited: - code.putln("%s;" % method_entry.type.declaration_code("(*%s)" % method_entry.cname)) - code.putln("};") + code.putln("%s;" % method_entry.type.declaration_code("(*%s)" % method_entry.cname)) + code.putln("};") def generate_exttype_vtabptr_declaration(self, entry, code): if not entry.used: @@ -1155,7 +1155,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): else: attr_type = attr.type code.putln( - "%s;" % attr_type.declaration_code(attr.cname)) + "%s;" % attr_type.declaration_code(attr.cname)) code.putln(footer) if type.objtypedef_cname is not None: # Only for exposing public typedef name. @@ -1164,15 +1164,15 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): def generate_c_class_declarations(self, env, code, definition): for entry in env.c_class_entries: if definition or entry.defined_in_pxd: - code.putln("static PyTypeObject *%s = 0;" % ( - entry.type.typeptr_cname)) + code.putln("static PyTypeObject *%s = 0;" % ( + entry.type.typeptr_cname)) def generate_cvariable_declarations(self, env, code, definition): if env.is_cython_builtin: return for entry in env.var_entries: if (entry.in_cinclude or entry.in_closure or - (entry.visibility == 'private' and not (entry.defined_in_pxd or entry.used))): + (entry.visibility == 'private' and not (entry.defined_in_pxd or entry.used))): continue storage_class = None @@ -1192,7 +1192,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): storage_class = "static" dll_linkage = None if entry.init is not None: - init = entry.type.literal_code(entry.init) + init = entry.type.literal_code(entry.init) type = entry.type cname = entry.cname @@ -1206,7 +1206,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): if storage_class: code.put("%s " % storage_class) code.put(type.declaration_code( - cname, dll_linkage=dll_linkage)) + cname, dll_linkage=dll_linkage)) if init is not None: code.put_safe(" = %s" % init) code.putln(";") @@ -1220,10 +1220,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): def generate_variable_definitions(self, env, code): for entry in env.var_entries: - if not entry.in_cinclude and entry.visibility == "public": + if not entry.in_cinclude and entry.visibility == "public": code.put(entry.type.declaration_code(entry.cname)) if entry.init is not None: - init = entry.type.literal_code(entry.init) + init = entry.type.literal_code(entry.init) code.put_safe(" = %s" % init) code.putln(";") @@ -1252,9 +1252,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): if scope.defines_any_special(["__setitem__", "__delitem__"]): self.generate_ass_subscript_function(scope, code) if scope.defines_any_special(["__getslice__", "__setslice__", "__delslice__"]): - warning(self.pos, - "__getslice__, __setslice__, and __delslice__ are not supported by Python 3, " - "use __getitem__, __setitem__, and __delitem__ instead", 1) + warning(self.pos, + "__getslice__, __setslice__, and __delslice__ are not supported by Python 3, " + "use __getitem__, __setitem__, and __delitem__ instead", 1) code.putln("#if PY_MAJOR_VERSION >= 3") code.putln("#error __getslice__, __setslice__, and __delslice__ not supported in Python 3.") code.putln("#endif") @@ -1269,7 +1269,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): if scope.defines_any_special(["__set__", "__delete__"]): self.generate_descr_set_function(scope, code) if not scope.is_closure_class_scope and scope.defines_any(["__dict__"]): - self.generate_dict_getter_function(scope, code) + self.generate_dict_getter_function(scope, code) if scope.defines_any_special(TypeSlots.richcmp_special_methods): self.generate_richcmp_function(scope, code) self.generate_property_accessors(scope, code) @@ -1290,7 +1290,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln( "%s = (%s)o;" % ( type.declaration_code("p"), - type.empty_declaration_code())) + type.empty_declaration_code())) def generate_new_function(self, scope, code, cclass_entry): tp_slot = TypeSlots.ConstructorSlot("tp_new", '__new__') @@ -1332,8 +1332,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln("static int %s = 0;" % freecount_name) code.putln("") code.putln( - "static PyObject *%s(PyTypeObject *t, %sPyObject *a, %sPyObject *k) {" % ( - slot_func, unused_marker, unused_marker)) + "static PyObject *%s(PyTypeObject *t, %sPyObject *a, %sPyObject *k) {" % ( + slot_func, unused_marker, unused_marker)) need_self_cast = (type.vtabslot_cname or (py_buffers or memoryview_slices or py_attrs) or @@ -1355,9 +1355,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): else: type_safety_check = ' & ((t->tp_flags & (Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_HEAPTYPE)) == 0)' obj_struct = type.declaration_code("", deref=True) - code.putln( - "if (CYTHON_COMPILING_IN_CPYTHON && likely((%s > 0) & (t->tp_basicsize == sizeof(%s))%s)) {" % ( - freecount_name, obj_struct, type_safety_check)) + code.putln( + "if (CYTHON_COMPILING_IN_CPYTHON && likely((%s > 0) & (t->tp_basicsize == sizeof(%s))%s)) {" % ( + freecount_name, obj_struct, type_safety_check)) code.putln("o = (PyObject*)%s[--%s];" % ( freelist_name, freecount_name)) code.putln("memset(o, 0, sizeof(%s));" % obj_struct) @@ -1379,10 +1379,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln("p = %s;" % type.cast_code("o")) #if need_self_cast: # self.generate_self_cast(scope, code) - - # from this point on, ensure DECREF(o) on failure - needs_error_cleanup = False - + + # from this point on, ensure DECREF(o) on failure + needs_error_cleanup = False + if type.vtabslot_cname: vtab_base_type = type while vtab_base_type.base_type and vtab_base_type.base_type.vtabstruct_cname: @@ -1396,16 +1396,16 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): struct_type_cast, type.vtabptr_cname)) for entry in cpp_class_attrs: - code.putln("new((void*)&(p->%s)) %s();" % ( - entry.cname, entry.type.empty_declaration_code())) + code.putln("new((void*)&(p->%s)) %s();" % ( + entry.cname, entry.type.empty_declaration_code())) for entry in py_attrs: - if entry.name == "__dict__": - needs_error_cleanup = True - code.put("p->%s = PyDict_New(); if (unlikely(!p->%s)) goto bad;" % ( - entry.cname, entry.cname)) - else: - code.put_init_var_to_py_none(entry, "p->%s", nanny=False) + if entry.name == "__dict__": + needs_error_cleanup = True + code.put("p->%s = PyDict_New(); if (unlikely(!p->%s)) goto bad;" % ( + entry.cname, entry.cname)) + else: + code.put_init_var_to_py_none(entry, "p->%s", nanny=False) for entry in memoryview_slices: code.putln("p->%s.data = NULL;" % entry.cname) @@ -1422,16 +1422,16 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): cinit_args = "o, %s, NULL" % Naming.empty_tuple else: cinit_args = "o, a, k" - needs_error_cleanup = True - code.putln("if (unlikely(%s(%s) < 0)) goto bad;" % ( - new_func_entry.func_cname, cinit_args)) - + needs_error_cleanup = True + code.putln("if (unlikely(%s(%s) < 0)) goto bad;" % ( + new_func_entry.func_cname, cinit_args)) + code.putln( "return o;") - if needs_error_cleanup: - code.putln("bad:") - code.put_decref_clear("o", py_object_type, nanny=False) - code.putln("return NULL;") + if needs_error_cleanup: + code.putln("bad:") + code.put_decref_clear("o", py_object_type, nanny=False) + code.putln("return NULL;") code.putln( "}") @@ -1455,14 +1455,14 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): weakref_slot = None dict_slot = scope.lookup_here("__dict__") if not scope.is_closure_class_scope else None - if dict_slot not in scope.var_entries: - dict_slot = None - + if dict_slot not in scope.var_entries: + dict_slot = None + _, (py_attrs, _, memoryview_slices) = scope.get_refcounted_entries() cpp_class_attrs = [entry for entry in scope.var_entries if entry.type.is_cpp_class] - if py_attrs or cpp_class_attrs or memoryview_slices or weakref_slot or dict_slot: + if py_attrs or cpp_class_attrs or memoryview_slices or weakref_slot or dict_slot: self.generate_self_cast(scope, code) if not is_final_type: @@ -1493,11 +1493,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): if weakref_slot: code.putln("if (p->__weakref__) PyObject_ClearWeakRefs(o);") - if dict_slot: - code.putln("if (p->__dict__) PyDict_Clear(p->__dict__);") - + if dict_slot: + code.putln("if (p->__dict__) PyDict_Clear(p->__dict__);") + for entry in cpp_class_attrs: - code.putln("__Pyx_call_destructor(p->%s);" % entry.cname) + code.putln("__Pyx_call_destructor(p->%s);" % entry.cname) for entry in py_attrs: code.put_xdecref_clear("p->%s" % entry.cname, entry.type, nanny=False, @@ -1514,7 +1514,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): if base_type.scope and base_type.scope.needs_gc(): code.putln("PyObject_GC_Track(o);") else: - code.putln("#if CYTHON_USE_TYPE_SLOTS") + code.putln("#if CYTHON_USE_TYPE_SLOTS") code.putln("if (PyType_IS_GC(Py_TYPE(o)->tp_base))") code.putln("#endif") code.putln("PyObject_GC_Track(o);") @@ -1548,12 +1548,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ' & ((Py_TYPE(o)->tp_flags & (Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_HEAPTYPE)) == 0)') type = scope.parent_type - code.putln( - "if (CYTHON_COMPILING_IN_CPYTHON && ((%s < %d) & (Py_TYPE(o)->tp_basicsize == sizeof(%s))%s)) {" % ( - freecount_name, - freelist_size, - type.declaration_code("", deref=True), - type_safety_check)) + code.putln( + "if (CYTHON_COMPILING_IN_CPYTHON && ((%s < %d) & (Py_TYPE(o)->tp_basicsize == sizeof(%s))%s)) {" % ( + freecount_name, + freelist_size, + type.declaration_code("", deref=True), + type_safety_check)) code.putln("%s[%s++] = %s;" % ( freelist_name, freecount_name, type.cast_code("o"))) code.putln("} else {") @@ -1584,10 +1584,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): slot_func = scope.mangle_internal("tp_traverse") base_type = scope.parent_type.base_type if tp_slot.slot_code(scope) != slot_func: - return # never used + return # never used code.putln("") code.putln( - "static int %s(PyObject *o, visitproc v, void *a) {" % slot_func) + "static int %s(PyObject *o, visitproc v, void *a) {" % slot_func) have_entries, (py_attrs, py_buffers, memoryview_slices) = ( scope.get_refcounted_entries(include_gc_simple=False)) @@ -1613,19 +1613,19 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): # the module cleanup, which may already have cleared it. # In that case, fall back to traversing the type hierarchy. base_cname = base_type.typeptr_cname - code.putln( - "e = ((likely(%s)) ? ((%s->tp_traverse) ? %s->tp_traverse(o, v, a) : 0) : " - "__Pyx_call_next_tp_traverse(o, v, a, %s)); if (e) return e;" % ( - base_cname, base_cname, base_cname, slot_func)) + code.putln( + "e = ((likely(%s)) ? ((%s->tp_traverse) ? %s->tp_traverse(o, v, a) : 0) : " + "__Pyx_call_next_tp_traverse(o, v, a, %s)); if (e) return e;" % ( + base_cname, base_cname, base_cname, slot_func)) code.globalstate.use_utility_code( UtilityCode.load_cached("CallNextTpTraverse", "ExtensionTypes.c")) for entry in py_attrs: var_code = "p->%s" % entry.cname var_as_pyobject = PyrexTypes.typecast(py_object_type, entry.type, var_code) - code.putln("if (%s) {" % var_code) + code.putln("if (%s) {" % var_code) code.putln("e = (*v)(%s, a); if (e) return e;" % var_as_pyobject) - code.putln("}") + code.putln("}") # Traverse buffer exporting objects. # Note: not traversing memoryview attributes of memoryview slices! @@ -1634,14 +1634,14 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): for entry in py_buffers: cname = entry.cname + ".obj" code.putln("if (p->%s) {" % cname) - code.putln("e = (*v)(p->%s, a); if (e) return e;" % cname) + code.putln("e = (*v)(p->%s, a); if (e) return e;" % cname) code.putln("}") - code.putln("return 0;") - code.putln("}") + code.putln("return 0;") + code.putln("}") def generate_clear_function(self, scope, code, cclass_entry): - tp_slot = TypeSlots.get_slot_by_name("tp_clear") + tp_slot = TypeSlots.get_slot_by_name("tp_clear") slot_func = scope.mangle_internal("tp_clear") base_type = scope.parent_type.base_type if tp_slot.slot_code(scope) != slot_func: @@ -1679,9 +1679,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): # the module cleanup, which may already have cleared it. # In that case, fall back to traversing the type hierarchy. base_cname = base_type.typeptr_cname - code.putln( - "if (likely(%s)) { if (%s->tp_clear) %s->tp_clear(o); } else __Pyx_call_next_tp_clear(o, %s);" % ( - base_cname, base_cname, base_cname, slot_func)) + code.putln( + "if (likely(%s)) { if (%s->tp_clear) %s->tp_clear(o); } else __Pyx_call_next_tp_clear(o, %s);" % ( + base_cname, base_cname, base_cname, slot_func)) code.globalstate.use_utility_code( UtilityCode.load_cached("CallNextTpClear", "ExtensionTypes.c")) @@ -1705,26 +1705,26 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): if cclass_entry.cname == '__pyx_memoryviewslice': code.putln("__PYX_XDEC_MEMVIEW(&p->from_slice, 1);") - code.putln("return 0;") - code.putln("}") + code.putln("return 0;") + code.putln("}") def generate_getitem_int_function(self, scope, code): # This function is put into the sq_item slot when # a __getitem__ method is present. It converts its # argument to a Python integer and calls mp_subscript. code.putln( - "static PyObject *%s(PyObject *o, Py_ssize_t i) {" % ( - scope.mangle_internal("sq_item"))) + "static PyObject *%s(PyObject *o, Py_ssize_t i) {" % ( + scope.mangle_internal("sq_item"))) code.putln( - "PyObject *r;") + "PyObject *r;") code.putln( - "PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0;") + "PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0;") code.putln( - "r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x);") + "r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x);") code.putln( - "Py_DECREF(x);") + "Py_DECREF(x);") code.putln( - "return r;") + "return r;") code.putln( "}") @@ -1737,40 +1737,40 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): del_entry = scope.lookup_here("__delitem__") code.putln("") code.putln( - "static int %s(PyObject *o, PyObject *i, PyObject *v) {" % ( - scope.mangle_internal("mp_ass_subscript"))) + "static int %s(PyObject *o, PyObject *i, PyObject *v) {" % ( + scope.mangle_internal("mp_ass_subscript"))) code.putln( - "if (v) {") + "if (v) {") if set_entry: - code.putln("return %s(o, i, v);" % set_entry.func_cname) + code.putln("return %s(o, i, v);" % set_entry.func_cname) else: self.generate_guarded_basetype_call( base_type, "tp_as_mapping", "mp_ass_subscript", "o, i, v", code) code.putln( - "PyErr_Format(PyExc_NotImplementedError,") + "PyErr_Format(PyExc_NotImplementedError,") code.putln( - ' "Subscript assignment not supported by %.200s", Py_TYPE(o)->tp_name);') + ' "Subscript assignment not supported by %.200s", Py_TYPE(o)->tp_name);') code.putln( - "return -1;") + "return -1;") code.putln( - "}") + "}") code.putln( - "else {") + "else {") if del_entry: code.putln( - "return %s(o, i);" % ( - del_entry.func_cname)) + "return %s(o, i);" % ( + del_entry.func_cname)) else: self.generate_guarded_basetype_call( base_type, "tp_as_mapping", "mp_ass_subscript", "o, i, v", code) code.putln( - "PyErr_Format(PyExc_NotImplementedError,") + "PyErr_Format(PyExc_NotImplementedError,") code.putln( - ' "Subscript deletion not supported by %.200s", Py_TYPE(o)->tp_name);') + ' "Subscript deletion not supported by %.200s", Py_TYPE(o)->tp_name);') code.putln( - "return -1;") + "return -1;") code.putln( - "}") + "}") code.putln( "}") @@ -1802,42 +1802,42 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): del_entry = scope.lookup_here("__delslice__") code.putln("") code.putln( - "static int %s(PyObject *o, Py_ssize_t i, Py_ssize_t j, PyObject *v) {" % ( - scope.mangle_internal("sq_ass_slice"))) + "static int %s(PyObject *o, Py_ssize_t i, Py_ssize_t j, PyObject *v) {" % ( + scope.mangle_internal("sq_ass_slice"))) code.putln( - "if (v) {") + "if (v) {") if set_entry: code.putln( - "return %s(o, i, j, v);" % ( - set_entry.func_cname)) + "return %s(o, i, j, v);" % ( + set_entry.func_cname)) else: self.generate_guarded_basetype_call( base_type, "tp_as_sequence", "sq_ass_slice", "o, i, j, v", code) code.putln( - "PyErr_Format(PyExc_NotImplementedError,") + "PyErr_Format(PyExc_NotImplementedError,") code.putln( - ' "2-element slice assignment not supported by %.200s", Py_TYPE(o)->tp_name);') + ' "2-element slice assignment not supported by %.200s", Py_TYPE(o)->tp_name);') code.putln( - "return -1;") + "return -1;") code.putln( - "}") + "}") code.putln( - "else {") + "else {") if del_entry: code.putln( - "return %s(o, i, j);" % ( - del_entry.func_cname)) + "return %s(o, i, j);" % ( + del_entry.func_cname)) else: self.generate_guarded_basetype_call( base_type, "tp_as_sequence", "sq_ass_slice", "o, i, j, v", code) code.putln( - "PyErr_Format(PyExc_NotImplementedError,") + "PyErr_Format(PyExc_NotImplementedError,") code.putln( - ' "2-element slice deletion not supported by %.200s", Py_TYPE(o)->tp_name);') + ' "2-element slice deletion not supported by %.200s", Py_TYPE(o)->tp_name);') code.putln( - "return -1;") + "return -1;") code.putln( - "}") + "}") code.putln( "}") @@ -1935,12 +1935,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): getattribute_entry = lookup_here_or_base("__getattribute__") code.putln("") code.putln( - "static PyObject *%s(PyObject *o, PyObject *n) {" % ( - scope.mangle_internal("tp_getattro"))) + "static PyObject *%s(PyObject *o, PyObject *n) {" % ( + scope.mangle_internal("tp_getattro"))) if getattribute_entry is not None: code.putln( - "PyObject *v = %s(o, n);" % ( - getattribute_entry.func_cname)) + "PyObject *v = %s(o, n);" % ( + getattribute_entry.func_cname)) else: if not has_instance_dict and scope.parent_type.is_final_type: # Final with no dict => use faster type attribute lookup. @@ -1962,8 +1962,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln( "PyErr_Clear();") code.putln( - "v = %s(o, n);" % ( - getattr_entry.func_cname)) + "v = %s(o, n);" % ( + getattr_entry.func_cname)) code.putln( "}") code.putln( @@ -1980,34 +1980,34 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): del_entry = scope.lookup_here("__delattr__") code.putln("") code.putln( - "static int %s(PyObject *o, PyObject *n, PyObject *v) {" % ( - scope.mangle_internal("tp_setattro"))) + "static int %s(PyObject *o, PyObject *n, PyObject *v) {" % ( + scope.mangle_internal("tp_setattro"))) code.putln( - "if (v) {") + "if (v) {") if set_entry: code.putln( - "return %s(o, n, v);" % ( - set_entry.func_cname)) + "return %s(o, n, v);" % ( + set_entry.func_cname)) else: self.generate_guarded_basetype_call( base_type, None, "tp_setattro", "o, n, v", code) code.putln( - "return PyObject_GenericSetAttr(o, n, v);") + "return PyObject_GenericSetAttr(o, n, v);") code.putln( - "}") + "}") code.putln( - "else {") + "else {") if del_entry: code.putln( - "return %s(o, n);" % ( - del_entry.func_cname)) + "return %s(o, n);" % ( + del_entry.func_cname)) else: self.generate_guarded_basetype_call( base_type, None, "tp_setattro", "o, n, v", code) code.putln( - "return PyObject_GenericSetAttr(o, n, 0);") + "return PyObject_GenericSetAttr(o, n, 0);") code.putln( - "}") + "}") code.putln( "}") @@ -2019,8 +2019,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): user_get_entry = scope.lookup_here("__get__") code.putln("") code.putln( - "static PyObject *%s(PyObject *o, PyObject *i, PyObject *c) {" % ( - scope.mangle_internal("tp_descr_get"))) + "static PyObject *%s(PyObject *o, PyObject *i, PyObject *c) {" % ( + scope.mangle_internal("tp_descr_get"))) code.putln( "PyObject *r = 0;") code.putln( @@ -2030,8 +2030,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): #code.put_incref("i", py_object_type) #code.put_incref("c", py_object_type) code.putln( - "r = %s(o, i, c);" % ( - user_get_entry.func_cname)) + "r = %s(o, i, c);" % ( + user_get_entry.func_cname)) #code.put_decref("i", py_object_type) #code.put_decref("c", py_object_type) code.putln( @@ -2048,38 +2048,38 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): user_del_entry = scope.lookup_here("__delete__") code.putln("") code.putln( - "static int %s(PyObject *o, PyObject *i, PyObject *v) {" % ( - scope.mangle_internal("tp_descr_set"))) + "static int %s(PyObject *o, PyObject *i, PyObject *v) {" % ( + scope.mangle_internal("tp_descr_set"))) code.putln( - "if (v) {") + "if (v) {") if user_set_entry: code.putln( - "return %s(o, i, v);" % ( - user_set_entry.func_cname)) + "return %s(o, i, v);" % ( + user_set_entry.func_cname)) else: self.generate_guarded_basetype_call( base_type, None, "tp_descr_set", "o, i, v", code) code.putln( - 'PyErr_SetString(PyExc_NotImplementedError, "__set__");') + 'PyErr_SetString(PyExc_NotImplementedError, "__set__");') code.putln( - "return -1;") + "return -1;") code.putln( - "}") + "}") code.putln( - "else {") + "else {") if user_del_entry: code.putln( - "return %s(o, i);" % ( - user_del_entry.func_cname)) + "return %s(o, i);" % ( + user_del_entry.func_cname)) else: self.generate_guarded_basetype_call( base_type, None, "tp_descr_set", "o, i, v", code) code.putln( - 'PyErr_SetString(PyExc_NotImplementedError, "__delete__");') + 'PyErr_SetString(PyExc_NotImplementedError, "__delete__");') code.putln( - "return -1;") + "return -1;") code.putln( - "}") + "}") code.putln( "}") @@ -2098,11 +2098,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): get_entry = property_scope.lookup_here("__get__") code.putln("") code.putln( - "static PyObject *%s(PyObject *o, CYTHON_UNUSED void *x) {" % ( - property_entry.getter_cname)) + "static PyObject *%s(PyObject *o, CYTHON_UNUSED void *x) {" % ( + property_entry.getter_cname)) code.putln( - "return %s(o);" % ( - get_entry.func_cname)) + "return %s(o);" % ( + get_entry.func_cname)) code.putln( "}") @@ -2114,34 +2114,34 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): del_entry = property_scope.lookup_here("__del__") code.putln("") code.putln( - "static int %s(PyObject *o, PyObject *v, CYTHON_UNUSED void *x) {" % ( - property_entry.setter_cname)) + "static int %s(PyObject *o, PyObject *v, CYTHON_UNUSED void *x) {" % ( + property_entry.setter_cname)) code.putln( - "if (v) {") + "if (v) {") if set_entry: code.putln( - "return %s(o, v);" % ( - set_entry.func_cname)) + "return %s(o, v);" % ( + set_entry.func_cname)) else: code.putln( - 'PyErr_SetString(PyExc_NotImplementedError, "__set__");') + 'PyErr_SetString(PyExc_NotImplementedError, "__set__");') code.putln( - "return -1;") + "return -1;") code.putln( - "}") + "}") code.putln( - "else {") + "else {") if del_entry: code.putln( - "return %s(o);" % ( - del_entry.func_cname)) + "return %s(o);" % ( + del_entry.func_cname)) else: code.putln( - 'PyErr_SetString(PyExc_NotImplementedError, "__del__");') + 'PyErr_SetString(PyExc_NotImplementedError, "__del__");') code.putln( - "return -1;") + "return -1;") code.putln( - "}") + "}") code.putln( "}") @@ -2167,7 +2167,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): else: objstruct = "struct %s" % type.objstruct_cname code.putln( - "sizeof(%s), /*tp_basicsize*/" % objstruct) + "sizeof(%s), /*tp_basicsize*/" % objstruct) code.putln( "0, /*tp_itemsize*/") for slot in TypeSlots.slot_table: @@ -2178,88 +2178,88 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): def generate_method_table(self, env, code): if env.is_c_class_scope and not env.pyfunc_entries: return - binding = env.directives['binding'] - + binding = env.directives['binding'] + code.putln("") - wrapper_code_writer = code.insertion_point() - + wrapper_code_writer = code.insertion_point() + code.putln( - "static PyMethodDef %s[] = {" % ( - env.method_table_cname)) + "static PyMethodDef %s[] = {" % ( + env.method_table_cname)) for entry in env.pyfunc_entries: - if not entry.fused_cfunction and not (binding and entry.is_overridable): - code.put_pymethoddef(entry, ",", wrapper_code_writer=wrapper_code_writer) + if not entry.fused_cfunction and not (binding and entry.is_overridable): + code.put_pymethoddef(entry, ",", wrapper_code_writer=wrapper_code_writer) code.putln( - "{0, 0, 0, 0}") + "{0, 0, 0, 0}") code.putln( "};") - if wrapper_code_writer.getvalue(): - wrapper_code_writer.putln("") - - def generate_dict_getter_function(self, scope, code): - dict_attr = scope.lookup_here("__dict__") - if not dict_attr or not dict_attr.is_variable: - return - func_name = scope.mangle_internal("__dict__getter") - dict_name = dict_attr.cname - code.putln("") - code.putln("static PyObject *%s(PyObject *o, CYTHON_UNUSED void *x) {" % func_name) - self.generate_self_cast(scope, code) - code.putln("if (unlikely(!p->%s)){" % dict_name) - code.putln("p->%s = PyDict_New();" % dict_name) - code.putln("}") - code.putln("Py_XINCREF(p->%s);" % dict_name) - code.putln("return p->%s;" % dict_name) - code.putln("}") - + if wrapper_code_writer.getvalue(): + wrapper_code_writer.putln("") + + def generate_dict_getter_function(self, scope, code): + dict_attr = scope.lookup_here("__dict__") + if not dict_attr or not dict_attr.is_variable: + return + func_name = scope.mangle_internal("__dict__getter") + dict_name = dict_attr.cname + code.putln("") + code.putln("static PyObject *%s(PyObject *o, CYTHON_UNUSED void *x) {" % func_name) + self.generate_self_cast(scope, code) + code.putln("if (unlikely(!p->%s)){" % dict_name) + code.putln("p->%s = PyDict_New();" % dict_name) + code.putln("}") + code.putln("Py_XINCREF(p->%s);" % dict_name) + code.putln("return p->%s;" % dict_name) + code.putln("}") + def generate_getset_table(self, env, code): if env.property_entries: code.putln("") code.putln( "static struct PyGetSetDef %s[] = {" % - env.getset_table_cname) + env.getset_table_cname) for entry in env.property_entries: - doc = entry.doc - if doc: - if doc.is_unicode: - doc = doc.as_utf8_string() - doc_code = doc.as_c_string_literal() + doc = entry.doc + if doc: + if doc.is_unicode: + doc = doc.as_utf8_string() + doc_code = doc.as_c_string_literal() else: doc_code = "0" code.putln( - '{(char *)"%s", %s, %s, (char *)%s, 0},' % ( + '{(char *)"%s", %s, %s, (char *)%s, 0},' % ( entry.name, entry.getter_cname or "0", entry.setter_cname or "0", doc_code)) code.putln( - "{0, 0, 0, 0, 0}") + "{0, 0, 0, 0, 0}") code.putln( "};") - def create_import_star_conversion_utility_code(self, env): - # Create all conversion helpers that are needed for "import *" assignments. - # Must be done before code generation to support CythonUtilityCode. - for name, entry in sorted(env.entries.items()): - if entry.is_cglobal and entry.used: - if not entry.type.is_pyobject: - entry.type.create_from_py_utility_code(env) - + def create_import_star_conversion_utility_code(self, env): + # Create all conversion helpers that are needed for "import *" assignments. + # Must be done before code generation to support CythonUtilityCode. + for name, entry in sorted(env.entries.items()): + if entry.is_cglobal and entry.used: + if not entry.type.is_pyobject: + entry.type.create_from_py_utility_code(env) + def generate_import_star(self, env, code): - env.use_utility_code(UtilityCode.load_cached("CStringEquals", "StringTools.c")) + env.use_utility_code(UtilityCode.load_cached("CStringEquals", "StringTools.c")) code.putln() - code.enter_cfunc_scope() # as we need labels - code.putln("static int %s(PyObject *o, PyObject* py_name, char *name) {" % Naming.import_star_set) - - code.putln("static const char* internal_type_names[] = {") + code.enter_cfunc_scope() # as we need labels + code.putln("static int %s(PyObject *o, PyObject* py_name, char *name) {" % Naming.import_star_set) + + code.putln("static const char* internal_type_names[] = {") for name, entry in sorted(env.entries.items()): if entry.is_type: code.putln('"%s",' % name) code.putln("0") code.putln("};") - - code.putln("const char** type_name = internal_type_names;") + + code.putln("const char** type_name = internal_type_names;") code.putln("while (*type_name) {") code.putln("if (__Pyx_StrEq(name, *type_name)) {") code.putln('PyErr_Format(PyExc_TypeError, "Cannot overwrite C type %s", name);') @@ -2267,17 +2267,17 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln("}") code.putln("type_name++;") code.putln("}") - + old_error_label = code.new_error_label() - code.putln("if (0);") # so the first one can be "else if" - msvc_count = 0 - for name, entry in sorted(env.entries.items()): - if entry.is_cglobal and entry.used and not entry.type.is_const: - msvc_count += 1 - if msvc_count % 100 == 0: - code.putln("#ifdef _MSC_VER") - code.putln("if (0); /* Workaround for MSVC C1061. */") - code.putln("#endif") + code.putln("if (0);") # so the first one can be "else if" + msvc_count = 0 + for name, entry in sorted(env.entries.items()): + if entry.is_cglobal and entry.used and not entry.type.is_const: + msvc_count += 1 + if msvc_count % 100 == 0: + code.putln("#ifdef _MSC_VER") + code.putln("if (0); /* Workaround for MSVC C1061. */") + code.putln("#endif") code.putln('else if (__Pyx_StrEq(name, "%s")) {' % name) if entry.type.is_pyobject: if entry.type.is_extension_type or entry.type.is_builtin_type: @@ -2289,13 +2289,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln("%s = %s;" % ( entry.cname, PyrexTypes.typecast(entry.type, py_object_type, "o"))) - elif entry.type.create_from_py_utility_code(env): - # if available, utility code was already created in self.prepare_utility_code() - code.putln(entry.type.from_py_call_code( - 'o', entry.cname, entry.pos, code)) + elif entry.type.create_from_py_utility_code(env): + # if available, utility code was already created in self.prepare_utility_code() + code.putln(entry.type.from_py_call_code( + 'o', entry.cname, entry.pos, code)) else: - code.putln('PyErr_Format(PyExc_TypeError, "Cannot convert Python object %s to %s");' % ( - name, entry.type)) + code.putln('PyErr_Format(PyExc_TypeError, "Cannot convert Python object %s to %s");' % ( + name, entry.type)) code.putln(code.error_goto(entry.pos)) code.putln("}") code.putln("else {") @@ -2310,17 +2310,17 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln("bad:") code.putln("return -1;") code.putln("}") - code.putln("") + code.putln("") code.putln(UtilityCode.load_as_string("ImportStar", "ImportExport.c")[1]) - code.exit_cfunc_scope() # done with labels + code.exit_cfunc_scope() # done with labels - def generate_module_init_func(self, imported_modules, env, options, code): + def generate_module_init_func(self, imported_modules, env, options, code): subfunction = self.mod_init_subfunction(self.pos, self.scope, code) - code.enter_cfunc_scope(self.scope) + code.enter_cfunc_scope(self.scope) code.putln("") code.putln(UtilityCode.load_as_string("PyModInitFuncType", "ModuleSetupCode.c")[0]) - init_name = 'init' + (options.init_suffix or env.module_name) + init_name = 'init' + (options.init_suffix or env.module_name) header2 = "__Pyx_PyMODINIT_FUNC %s(void)" % init_name header3 = "__Pyx_PyMODINIT_FUNC %s(void)" % self.mod_init_func_cname('PyInit', env, options) code.putln("#if PY_MAJOR_VERSION < 3") @@ -2342,7 +2342,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln("") # main module init code lives in Py_mod_exec function, not in PyInit function - code.putln("static CYTHON_SMALL_CODE int %s(PyObject *%s)" % ( + code.putln("static CYTHON_SMALL_CODE int %s(PyObject *%s)" % ( self.mod_init_func_cname(Naming.pymodule_exec_func_cname, env), Naming.pymodinit_module_arg)) code.putln("#endif") # PEP489 @@ -2354,26 +2354,26 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): tempdecl_code = code.insertion_point() - profile = code.globalstate.directives['profile'] - linetrace = code.globalstate.directives['linetrace'] - if profile or linetrace: - code.globalstate.use_utility_code(UtilityCode.load_cached("Profile", "Profile.c")) - + profile = code.globalstate.directives['profile'] + linetrace = code.globalstate.directives['linetrace'] + if profile or linetrace: + code.globalstate.use_utility_code(UtilityCode.load_cached("Profile", "Profile.c")) + code.put_declare_refcount_context() code.putln("#if CYTHON_PEP489_MULTI_PHASE_INIT") - # Most extension modules simply can't deal with it, and Cython isn't ready either. - # See issues listed here: https://docs.python.org/3/c-api/init.html#sub-interpreter-support - code.putln("if (%s) {" % Naming.module_cname) + # Most extension modules simply can't deal with it, and Cython isn't ready either. + # See issues listed here: https://docs.python.org/3/c-api/init.html#sub-interpreter-support + code.putln("if (%s) {" % Naming.module_cname) # Hack: enforce single initialisation. - code.putln("if (%s == %s) return 0;" % ( + code.putln("if (%s == %s) return 0;" % ( Naming.module_cname, Naming.pymodinit_module_arg, )) - code.putln('PyErr_SetString(PyExc_RuntimeError,' - ' "Module \'%s\' has already been imported. Re-initialisation is not supported.");' % - env.module_name) - code.putln("return -1;") - code.putln("}") + code.putln('PyErr_SetString(PyExc_RuntimeError,' + ' "Module \'%s\' has already been imported. Re-initialisation is not supported.");' % + env.module_name) + code.putln("return -1;") + code.putln("}") code.putln("#elif PY_MAJOR_VERSION >= 3") # Hack: enforce single initialisation also on reimports under different names on Python 3 (with PEP 3121/489). code.putln("if (%s) return __Pyx_NewRef(%s);" % ( @@ -2382,31 +2382,31 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): )) code.putln("#endif") - if profile or linetrace: - tempdecl_code.put_trace_declarations() - code.put_trace_frame_init() - + if profile or linetrace: + tempdecl_code.put_trace_declarations() + code.put_trace_frame_init() + refnanny_import_code = UtilityCode.load_as_string("ImportRefnannyAPI", "ModuleSetupCode.c")[1] code.putln(refnanny_import_code.rstrip()) code.put_setup_refcount_context(header3) env.use_utility_code(UtilityCode.load("CheckBinaryVersion", "ModuleSetupCode.c")) - code.put_error_if_neg(self.pos, "__Pyx_check_binary_version()") - - code.putln("#ifdef __Pxy_PyFrame_Initialize_Offsets") - code.putln("__Pxy_PyFrame_Initialize_Offsets();") - code.putln("#endif") - code.putln("%s = PyTuple_New(0); %s" % ( - Naming.empty_tuple, code.error_goto_if_null(Naming.empty_tuple, self.pos))) - code.putln("%s = PyBytes_FromStringAndSize(\"\", 0); %s" % ( - Naming.empty_bytes, code.error_goto_if_null(Naming.empty_bytes, self.pos))) - code.putln("%s = PyUnicode_FromStringAndSize(\"\", 0); %s" % ( - Naming.empty_unicode, code.error_goto_if_null(Naming.empty_unicode, self.pos))) + code.put_error_if_neg(self.pos, "__Pyx_check_binary_version()") + + code.putln("#ifdef __Pxy_PyFrame_Initialize_Offsets") + code.putln("__Pxy_PyFrame_Initialize_Offsets();") + code.putln("#endif") + code.putln("%s = PyTuple_New(0); %s" % ( + Naming.empty_tuple, code.error_goto_if_null(Naming.empty_tuple, self.pos))) + code.putln("%s = PyBytes_FromStringAndSize(\"\", 0); %s" % ( + Naming.empty_bytes, code.error_goto_if_null(Naming.empty_bytes, self.pos))) + code.putln("%s = PyUnicode_FromStringAndSize(\"\", 0); %s" % ( + Naming.empty_unicode, code.error_goto_if_null(Naming.empty_unicode, self.pos))) for ext_type in ('CyFunction', 'FusedFunction', 'Coroutine', 'Generator', 'AsyncGen', 'StopAsyncIteration'): - code.putln("#ifdef __Pyx_%s_USED" % ext_type) - code.put_error_if_neg(self.pos, "__pyx_%s_init()" % ext_type) - code.putln("#endif") + code.putln("#ifdef __Pyx_%s_USED" % ext_type) + code.put_error_if_neg(self.pos, "__pyx_%s_init()" % ext_type) + code.putln("#endif") code.putln("/*--- Library function declarations ---*/") if env.directives['np_pythran']: @@ -2419,21 +2419,21 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln("#endif") code.putln("/*--- Module creation code ---*/") - self.generate_module_creation_code(env, options, code) + self.generate_module_creation_code(env, options, code) code.putln("/*--- Initialize various global constants etc. ---*/") - code.put_error_if_neg(self.pos, "__Pyx_InitGlobals()") + code.put_error_if_neg(self.pos, "__Pyx_InitGlobals()") - code.putln("#if PY_MAJOR_VERSION < 3 && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || " - "__PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT)") - code.put_error_if_neg(self.pos, "__Pyx_init_sys_getdefaultencoding_params()") + code.putln("#if PY_MAJOR_VERSION < 3 && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || " + "__PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT)") + code.put_error_if_neg(self.pos, "__Pyx_init_sys_getdefaultencoding_params()") code.putln("#endif") code.putln("if (%s%s) {" % (Naming.module_is_main, self.full_module_name.replace('.', '__'))) - code.put_error_if_neg(self.pos, 'PyObject_SetAttr(%s, %s, %s)' % ( - env.module_cname, - code.intern_identifier(EncodedString("__name__")), - code.intern_identifier(EncodedString("__main__")))) + code.put_error_if_neg(self.pos, 'PyObject_SetAttr(%s, %s, %s)' % ( + env.module_cname, + code.intern_identifier(EncodedString("__name__")), + code.intern_identifier(EncodedString("__main__")))) code.putln("}") # set up __file__ and __path__, then add the module to sys.modules @@ -2476,20 +2476,20 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln("/*--- Execution code ---*/") code.mark_pos(None) - code.putln("#if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED)") - code.put_error_if_neg(self.pos, "__Pyx_patch_abc()") - code.putln("#endif") - - if profile or linetrace: - code.put_trace_call(header3, self.pos, nogil=not code.funcstate.gil_owned) - code.funcstate.can_trace = True - + code.putln("#if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED)") + code.put_error_if_neg(self.pos, "__Pyx_patch_abc()") + code.putln("#endif") + + if profile or linetrace: + code.put_trace_call(header3, self.pos, nogil=not code.funcstate.gil_owned) + code.funcstate.can_trace = True + self.body.generate_execution_code(code) - if profile or linetrace: - code.funcstate.can_trace = False - code.put_trace_return("Py_None", nogil=not code.funcstate.gil_owned) - + if profile or linetrace: + code.funcstate.can_trace = False + code.put_trace_return("Py_None", nogil=not code.funcstate.gil_owned) + code.putln() code.putln("/*--- Wrapped vars code ---*/") self.generate_wrapped_entries_code(env, code) @@ -2506,15 +2506,15 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.put_xdecref(cname, type) code.putln('if (%s) {' % env.module_cname) code.putln('if (%s) {' % env.module_dict_cname) - code.put_add_traceback("init %s" % env.qualified_name) + code.put_add_traceback("init %s" % env.qualified_name) code.globalstate.use_utility_code(Nodes.traceback_utility_code) - # Module reference and module dict are in global variables which might still be needed - # for cleanup, atexit code, etc., so leaking is better than crashing. - # At least clearing the module dict here might be a good idea, but could still break - # user code in atexit or other global registries. - ##code.put_decref_clear(env.module_dict_cname, py_object_type, nanny=False) + # Module reference and module dict are in global variables which might still be needed + # for cleanup, atexit code, etc., so leaking is better than crashing. + # At least clearing the module dict here might be a good idea, but could still break + # user code in atexit or other global registries. + ##code.put_decref_clear(env.module_dict_cname, py_object_type, nanny=False) code.putln('}') - code.put_decref_clear(env.module_cname, py_object_type, nanny=False, clear_before_decref=True) + code.put_decref_clear(env.module_cname, py_object_type, nanny=False, clear_before_decref=True) code.putln('} else if (!PyErr_Occurred()) {') code.putln('PyErr_SetString(PyExc_ImportError, "init %s");' % env.qualified_name) code.putln('}') @@ -2562,7 +2562,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): self.call_code = orig_code.insertion_point() code = function_code code.enter_cfunc_scope(scope) - prototypes.putln("static CYTHON_SMALL_CODE int %s(void); /*proto*/" % self.cfunc_name) + prototypes.putln("static CYTHON_SMALL_CODE int %s(void); /*proto*/" % self.cfunc_name) code.putln("static int %s(void) {" % self.cfunc_name) code.put_declare_refcount_context() self.tempdecl_code = code.insertion_point() @@ -2730,11 +2730,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): # if entry.type.is_pyobject and entry.used: # code.putln("Py_DECREF(%s); %s = 0;" % ( # code.entry_as_pyobject(entry), entry.cname)) - if Options.pre_import is not None: - code.put_decref_clear(Naming.preimport_cname, py_object_type, - nanny=False, clear_before_decref=True) - for cname in [env.module_dict_cname, Naming.cython_runtime_cname, Naming.builtins_cname]: - code.put_decref_clear(cname, py_object_type, nanny=False, clear_before_decref=True) + if Options.pre_import is not None: + code.put_decref_clear(Naming.preimport_cname, py_object_type, + nanny=False, clear_before_decref=True) + for cname in [env.module_dict_cname, Naming.cython_runtime_cname, Naming.builtins_cname]: + code.put_decref_clear(cname, py_object_type, nanny=False, clear_before_decref=True) def generate_main_method(self, env, code): module_is_main = "%s%s" % (Naming.module_is_main, self.full_module_name.replace('.', '__')) @@ -2742,18 +2742,18 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): wmain = "wmain" else: wmain = Options.embed - main_method = UtilityCode.load_cached("MainFunction", "Embed.c") + main_method = UtilityCode.load_cached("MainFunction", "Embed.c") code.globalstate.use_utility_code( main_method.specialize( - module_name=env.module_name, - module_is_main=module_is_main, - main_method=Options.embed, - wmain_method=wmain)) + module_name=env.module_name, + module_is_main=module_is_main, + main_method=Options.embed, + wmain_method=wmain)) def mod_init_func_cname(self, prefix, env, options=None): - return '%s_%s' % (prefix, options and options.init_suffix or env.module_name) + return '%s_%s' % (prefix, options and options.init_suffix or env.module_name) - def generate_pymoduledef_struct(self, env, options, code): + def generate_pymoduledef_struct(self, env, options, code): if env.doc: doc = "%s" % code.get_string_const(env.doc) else: @@ -2781,7 +2781,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln("") code.putln("static struct PyModuleDef %s = {" % Naming.pymoduledef_cname) code.putln(" PyModuleDef_HEAD_INIT,") - code.putln(' "%s",' % (options.module_name or env.module_name)) + code.putln(' "%s",' % (options.module_name or env.module_name)) code.putln(" %s, /* m_doc */" % doc) code.putln("#if CYTHON_PEP489_MULTI_PHASE_INIT") code.putln(" 0, /* m_size */") @@ -2800,7 +2800,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln("};") code.putln("#endif") - def generate_module_creation_code(self, env, options, code): + def generate_module_creation_code(self, env, options, code): # Generate code to create the module object and # install the builtins. if env.doc: @@ -2818,7 +2818,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln( '%s = Py_InitModule4("%s", %s, %s, 0, PYTHON_API_VERSION); Py_XINCREF(%s);' % ( env.module_cname, - options.module_name or env.module_name, + options.module_name or env.module_name, env.method_table_cname, doc, env.module_cname)) @@ -2841,12 +2841,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): '%s = PyImport_AddModule(__Pyx_BUILTIN_MODULE_NAME); %s' % ( Naming.builtins_cname, code.error_goto_if_null(Naming.builtins_cname, self.pos))) - code.put_incref(Naming.builtins_cname, py_object_type, nanny=False) + code.put_incref(Naming.builtins_cname, py_object_type, nanny=False) code.putln( '%s = PyImport_AddModule((char *) "cython_runtime"); %s' % ( Naming.cython_runtime_cname, code.error_goto_if_null(Naming.cython_runtime_cname, self.pos))) - code.put_incref(Naming.cython_runtime_cname, py_object_type, nanny=False) + code.put_incref(Naming.cython_runtime_cname, py_object_type, nanny=False) code.putln( 'if (PyObject_SetAttrString(%s, "__builtins__", %s) < 0) %s;' % ( env.module_cname, @@ -2858,7 +2858,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): Naming.preimport_cname, Options.pre_import, code.error_goto_if_null(Naming.preimport_cname, self.pos))) - code.put_incref(Naming.preimport_cname, py_object_type, nanny=False) + code.put_incref(Naming.preimport_cname, py_object_type, nanny=False) def generate_global_init_code(self, env, code): # Generate code to initialise global PyObject * @@ -2869,7 +2869,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): entry.type.global_init_code(entry, code) def generate_wrapped_entries_code(self, env, code): - for name, entry in sorted(env.entries.items()): + for name, entry in sorted(env.entries.items()): if (entry.create_wrapper and not entry.is_type and entry.scope is env): @@ -2892,13 +2892,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): entries = [] for entry in env.var_entries: if (entry.api - or entry.defined_in_pxd - or (Options.cimport_from_pyx and not entry.visibility == 'extern')): + or entry.defined_in_pxd + or (Options.cimport_from_pyx and not entry.visibility == 'extern')): entries.append(entry) if entries: env.use_utility_code(UtilityCode.load_cached("VoidPtrExport", "ImportExport.c")) for entry in entries: - signature = entry.type.empty_declaration_code() + signature = entry.type.empty_declaration_code() name = code.intern_identifier(entry.name) code.putln('if (__Pyx_ExportVoidPtr(%s, (void *)&%s, "%s") < 0) %s' % ( name, entry.cname, signature, @@ -2909,14 +2909,14 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): entries = [] for entry in env.cfunc_entries: if (entry.api - or entry.defined_in_pxd - or (Options.cimport_from_pyx and not entry.visibility == 'extern')): + or entry.defined_in_pxd + or (Options.cimport_from_pyx and not entry.visibility == 'extern')): entries.append(entry) if entries: env.use_utility_code( UtilityCode.load_cached("FunctionExport", "ImportExport.c")) - # Note: while this looks like it could be more cheaply stored and read from a struct array, - # investigation shows that the resulting binary is smaller with repeated functions calls. + # Note: while this looks like it could be more cheaply stored and read from a struct array, + # investigation shows that the resulting binary is smaller with repeated functions calls. for entry in entries: signature = entry.type.signature_string() code.putln('if (__Pyx_ExportFunction("%s", (void (*)(void))%s, "%s") < 0) %s' % ( @@ -2929,10 +2929,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): # Generate type import code for all exported extension types in # an imported module. #if module.c_class_entries: - with ModuleImportGenerator(code) as import_generator: - for entry in module.c_class_entries: - if entry.defined_in_pxd: - self.generate_type_import_code(env, entry.type, entry.pos, code, import_generator) + with ModuleImportGenerator(code) as import_generator: + for entry in module.c_class_entries: + if entry.defined_in_pxd: + self.generate_type_import_code(env, entry.type, entry.pos, code, import_generator) def specialize_fused_types(self, pxd_env): """ @@ -2957,7 +2957,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): UtilityCode.load_cached("VoidPtrImport", "ImportExport.c")) temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True) code.putln( - '%s = PyImport_ImportModule("%s"); if (!%s) %s' % ( + '%s = PyImport_ImportModule("%s"); if (!%s) %s' % ( temp, module.qualified_name, temp, @@ -2968,7 +2968,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): cname = entry.cname else: cname = module.mangle(Naming.varptr_prefix, entry.name) - signature = entry.type.empty_declaration_code() + signature = entry.type.empty_declaration_code() code.putln( 'if (__Pyx_ImportVoidPtr(%s, "%s", (void **)&%s, "%s") < 0) %s' % ( temp, entry.name, cname, signature, @@ -2987,7 +2987,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): UtilityCode.load_cached("FunctionImport", "ImportExport.c")) temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True) code.putln( - '%s = PyImport_ImportModule("%s"); if (!%s) %s' % ( + '%s = PyImport_ImportModule("%s"); if (!%s) %s' % ( temp, module.qualified_name, temp, @@ -3007,33 +3007,33 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): def generate_type_init_code(self, env, code): # Generate type import code for extern extension types # and type ready code for non-extern ones. - with ModuleImportGenerator(code) as import_generator: - for entry in env.c_class_entries: - if entry.visibility == 'extern' and not entry.utility_code_definition: - self.generate_type_import_code(env, entry.type, entry.pos, code, import_generator) - else: - self.generate_base_type_import_code(env, entry, code, import_generator) - self.generate_exttype_vtable_init_code(entry, code) - if entry.type.early_init: - self.generate_type_ready_code(entry, code) - - def generate_base_type_import_code(self, env, entry, code, import_generator): + with ModuleImportGenerator(code) as import_generator: + for entry in env.c_class_entries: + if entry.visibility == 'extern' and not entry.utility_code_definition: + self.generate_type_import_code(env, entry.type, entry.pos, code, import_generator) + else: + self.generate_base_type_import_code(env, entry, code, import_generator) + self.generate_exttype_vtable_init_code(entry, code) + if entry.type.early_init: + self.generate_type_ready_code(entry, code) + + def generate_base_type_import_code(self, env, entry, code, import_generator): base_type = entry.type.base_type if (base_type and base_type.module_name != env.qualified_name and not - base_type.is_builtin_type and not entry.utility_code_definition): - self.generate_type_import_code(env, base_type, self.pos, code, import_generator) + base_type.is_builtin_type and not entry.utility_code_definition): + self.generate_type_import_code(env, base_type, self.pos, code, import_generator) - def generate_type_import_code(self, env, type, pos, code, import_generator): + def generate_type_import_code(self, env, type, pos, code, import_generator): # If not already done, generate code to import the typeobject of an # extension type defined in another module, and extract its C method # table pointer if any. if type in env.types_imported: return - if type.name not in Code.ctypedef_builtins_map: - # see corresponding condition in generate_type_import_call() below! - code.globalstate.use_utility_code( - UtilityCode.load_cached("TypeImport", "ImportExport.c")) - self.generate_type_import_call(type, code, import_generator, error_pos=pos) + if type.name not in Code.ctypedef_builtins_map: + # see corresponding condition in generate_type_import_call() below! + code.globalstate.use_utility_code( + UtilityCode.load_cached("TypeImport", "ImportExport.c")) + self.generate_type_import_call(type, code, import_generator, error_pos=pos) if type.vtabptr_cname: code.globalstate.use_utility_code( UtilityCode.load_cached('GetVTable', 'ImportExport.c')) @@ -3044,7 +3044,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.error_goto_if_null(type.vtabptr_cname, pos))) env.types_imported.add(type) - def generate_type_import_call(self, type, code, import_generator, error_code=None, error_pos=None): + def generate_type_import_call(self, type, code, import_generator, error_code=None, error_pos=None): if type.typedef_flag: objstruct = type.objstruct_cname else: @@ -3054,11 +3054,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): condition = replacement = None if module_name not in ('__builtin__', 'builtins'): module_name = '"%s"' % module_name - elif type.name in Code.ctypedef_builtins_map: - # Fast path for special builtins, don't actually import - ctypename = Code.ctypedef_builtins_map[type.name] - code.putln('%s = %s;' % (type.typeptr_cname, ctypename)) - return + elif type.name in Code.ctypedef_builtins_map: + # Fast path for special builtins, don't actually import + ctypename = Code.ctypedef_builtins_map[type.name] + code.putln('%s = %s;' % (type.typeptr_cname, ctypename)) + return else: module_name = '__Pyx_BUILTIN_MODULE_NAME' if type.name in Code.non_portable_builtins_map: @@ -3067,14 +3067,14 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): # Some builtin types have a tp_basicsize which differs from sizeof(...): sizeof_objstruct = Code.basicsize_builtins_map[objstruct] - if not error_code: - assert error_pos is not None - error_code = code.error_goto(error_pos) - - module = import_generator.imported_module(module_name, error_code) - code.put('%s = __Pyx_ImportType(%s, %s,' % ( + if not error_code: + assert error_pos is not None + error_code = code.error_goto(error_pos) + + module = import_generator.imported_module(module_name, error_code) + code.put('%s = __Pyx_ImportType(%s, %s,' % ( type.typeptr_cname, - module, + module, module_name)) if condition and replacement: @@ -3090,7 +3090,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): if sizeof_objstruct != objstruct: if not condition: code.putln("") # start in new line - code.putln("#if defined(PYPY_VERSION_NUM) && PYPY_VERSION_NUM < 0x050B0000") + code.putln("#if defined(PYPY_VERSION_NUM) && PYPY_VERSION_NUM < 0x050B0000") code.putln('sizeof(%s),' % objstruct) code.putln("#else") code.putln('sizeof(%s),' % sizeof_objstruct) @@ -3098,18 +3098,18 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): else: code.put('sizeof(%s), ' % objstruct) - # check_size - if type.check_size and type.check_size in ('error', 'warn', 'ignore'): - check_size = type.check_size - elif not type.is_external or type.is_subclassed: - check_size = 'error' - else: - raise RuntimeError("invalid value for check_size '%s' when compiling %s.%s" % ( - type.check_size, module_name, type.name)) - code.putln('__Pyx_ImportType_CheckSize_%s);' % check_size.title()) - - code.putln(' if (!%s) %s' % (type.typeptr_cname, error_code)) - + # check_size + if type.check_size and type.check_size in ('error', 'warn', 'ignore'): + check_size = type.check_size + elif not type.is_external or type.is_subclassed: + check_size = 'error' + else: + raise RuntimeError("invalid value for check_size '%s' when compiling %s.%s" % ( + type.check_size, module_name, type.name)) + code.putln('__Pyx_ImportType_CheckSize_%s);' % check_size.title()) + + code.putln(' if (!%s) %s' % (type.typeptr_cname, error_code)) + def generate_type_ready_code(self, entry, code): Nodes.CClassDefNode.generate_type_ready_code(entry, code) @@ -3131,7 +3131,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): c_method_entries = [ entry for entry in type.scope.cfunc_entries - if entry.func_cname] + if entry.func_cname] if c_method_entries: for meth_entry in c_method_entries: cast = meth_entry.type.signature_cast_string() @@ -3142,47 +3142,47 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): cast, meth_entry.func_cname)) - -class ModuleImportGenerator(object): - """ - Helper to generate module import while importing external types. - This is used to avoid excessive re-imports of external modules when multiple types are looked up. - """ - def __init__(self, code, imported_modules=None): - self.code = code - self.imported = {} - if imported_modules: - for name, cname in imported_modules.items(): - self.imported['"%s"' % name] = cname - self.temps = [] # remember original import order for freeing - - def imported_module(self, module_name_string, error_code): - if module_name_string in self.imported: - return self.imported[module_name_string] - - code = self.code - temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True) - self.temps.append(temp) - code.putln('%s = PyImport_ImportModule(%s); if (unlikely(!%s)) %s' % ( - temp, module_name_string, temp, error_code)) - code.put_gotref(temp) - self.imported[module_name_string] = temp - return temp - - def __enter__(self): - return self - - def __exit__(self, *exc): - code = self.code - for temp in self.temps: - code.put_decref_clear(temp, py_object_type) - code.funcstate.release_temp(temp) - - + +class ModuleImportGenerator(object): + """ + Helper to generate module import while importing external types. + This is used to avoid excessive re-imports of external modules when multiple types are looked up. + """ + def __init__(self, code, imported_modules=None): + self.code = code + self.imported = {} + if imported_modules: + for name, cname in imported_modules.items(): + self.imported['"%s"' % name] = cname + self.temps = [] # remember original import order for freeing + + def imported_module(self, module_name_string, error_code): + if module_name_string in self.imported: + return self.imported[module_name_string] + + code = self.code + temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True) + self.temps.append(temp) + code.putln('%s = PyImport_ImportModule(%s); if (unlikely(!%s)) %s' % ( + temp, module_name_string, temp, error_code)) + code.put_gotref(temp) + self.imported[module_name_string] = temp + return temp + + def __enter__(self): + return self + + def __exit__(self, *exc): + code = self.code + for temp in self.temps: + code.put_decref_clear(temp, py_object_type) + code.funcstate.release_temp(temp) + + def generate_cfunction_declaration(entry, env, code, definition): from_cy_utility = entry.used and entry.utility_code_definition - if entry.used and entry.inline_func_in_pxd or (not entry.in_cinclude and ( - definition or entry.defined_in_pxd or entry.visibility == 'extern' or from_cy_utility)): + if entry.used and entry.inline_func_in_pxd or (not entry.in_cinclude and ( + definition or entry.defined_in_pxd or entry.visibility == 'extern' or from_cy_utility)): if entry.visibility == 'extern': storage_class = Naming.extern_c_macro dll_linkage = "DL_IMPORT" @@ -3203,7 +3203,7 @@ def generate_cfunction_declaration(entry, env, code, definition): type = CPtrType(type) header = type.declaration_code( - entry.cname, dll_linkage=dll_linkage) + entry.cname, dll_linkage=dll_linkage) modifiers = code.build_function_modifiers(entry.func_modifiers) code.putln("%s %s%s; /*proto*/" % ( storage_class, @@ -3216,7 +3216,7 @@ def generate_cfunction_declaration(entry, env, code, definition): # #------------------------------------------------------------------------------------ -refnanny_utility_code = UtilityCode.load("Refnanny", "ModuleSetupCode.c") +refnanny_utility_code = UtilityCode.load("Refnanny", "ModuleSetupCode.c") packed_struct_utility_code = UtilityCode(proto=""" #if defined(__GNUC__) diff --git a/contrib/tools/cython/Cython/Compiler/Naming.py b/contrib/tools/cython/Cython/Compiler/Naming.py index 68afd2b21c..2c9b620788 100644 --- a/contrib/tools/cython/Cython/Compiler/Naming.py +++ b/contrib/tools/cython/Cython/Compiler/Naming.py @@ -18,7 +18,7 @@ arg_prefix = pyrex_prefix + "arg_" funcdoc_prefix = pyrex_prefix + "doc_" enum_prefix = pyrex_prefix + "e_" func_prefix = pyrex_prefix + "f_" -func_prefix_api = pyrex_prefix + "api_f_" +func_prefix_api = pyrex_prefix + "api_f_" pyfunc_prefix = pyrex_prefix + "pf_" pywrap_prefix = pyrex_prefix + "pw_" genbody_prefix = pyrex_prefix + "gb_" @@ -28,7 +28,7 @@ const_prefix = pyrex_prefix + "k_" py_const_prefix = pyrex_prefix + "kp_" label_prefix = pyrex_prefix + "L" pymethdef_prefix = pyrex_prefix + "mdef_" -method_wrapper_prefix = pyrex_prefix + "specialmethod_" +method_wrapper_prefix = pyrex_prefix + "specialmethod_" methtab_prefix = pyrex_prefix + "methods_" memtab_prefix = pyrex_prefix + "members_" objstruct_prefix = pyrex_prefix + "obj_" @@ -38,7 +38,7 @@ type_prefix = pyrex_prefix + "t_" typeobj_prefix = pyrex_prefix + "type_" var_prefix = pyrex_prefix + "v_" varptr_prefix = pyrex_prefix + "vp_" -varptr_prefix_api = pyrex_prefix + "api_vp_" +varptr_prefix_api = pyrex_prefix + "api_vp_" wrapperbase_prefix= pyrex_prefix + "wrapperbase_" pybuffernd_prefix = pyrex_prefix + "pybuffernd_" pybufferstruct_prefix = pyrex_prefix + "pybuffer_" @@ -62,10 +62,10 @@ interned_prefixes = { 'codeobj': pyrex_prefix + "codeobj_", 'slice': pyrex_prefix + "slice_", 'ustring': pyrex_prefix + "ustring_", - 'umethod': pyrex_prefix + "umethod_", + 'umethod': pyrex_prefix + "umethod_", } -ctuple_type_prefix = pyrex_prefix + "ctuple_" +ctuple_type_prefix = pyrex_prefix + "ctuple_" args_cname = pyrex_prefix + "args" generator_cname = pyrex_prefix + "generator" sent_value_cname = pyrex_prefix + "sent_value" @@ -83,7 +83,7 @@ kwds_cname = pyrex_prefix + "kwds" lineno_cname = pyrex_prefix + "lineno" clineno_cname = pyrex_prefix + "clineno" cfilenm_cname = pyrex_prefix + "cfilenm" -local_tstate_cname = pyrex_prefix + "tstate" +local_tstate_cname = pyrex_prefix + "tstate" module_cname = pyrex_prefix + "m" moddoc_cname = pyrex_prefix + "mdoc" methtable_cname = pyrex_prefix + "methods" @@ -97,7 +97,7 @@ gilstate_cname = pyrex_prefix + "state" skip_dispatch_cname = pyrex_prefix + "skip_dispatch" empty_tuple = pyrex_prefix + "empty_tuple" empty_bytes = pyrex_prefix + "empty_bytes" -empty_unicode = pyrex_prefix + "empty_unicode" +empty_unicode = pyrex_prefix + "empty_unicode" print_function = pyrex_prefix + "print" print_function_kwargs = pyrex_prefix + "print_kwargs" cleanup_cname = pyrex_prefix + "module_cleanup" @@ -117,9 +117,9 @@ frame_code_cname = pyrex_prefix + "frame_code" binding_cfunc = pyrex_prefix + "binding_PyCFunctionType" fused_func_prefix = pyrex_prefix + 'fuse_' quick_temp_cname = pyrex_prefix + "temp" # temp variable for quick'n'dirty temping -tp_dict_version_temp = pyrex_prefix + "tp_dict_version" -obj_dict_version_temp = pyrex_prefix + "obj_dict_version" -type_dict_guard_temp = pyrex_prefix + "type_dict_guard" +tp_dict_version_temp = pyrex_prefix + "tp_dict_version" +obj_dict_version_temp = pyrex_prefix + "obj_dict_version" +type_dict_guard_temp = pyrex_prefix + "type_dict_guard" cython_runtime_cname = pyrex_prefix + "cython_runtime" global_code_object_cache_find = pyrex_prefix + 'find_code_object' diff --git a/contrib/tools/cython/Cython/Compiler/Nodes.py b/contrib/tools/cython/Cython/Compiler/Nodes.py index 6fbad234c7..6436c5002d 100644 --- a/contrib/tools/cython/Cython/Compiler/Nodes.py +++ b/contrib/tools/cython/Cython/Compiler/Nodes.py @@ -22,22 +22,22 @@ from . import PyrexTypes from . import TypeSlots from .PyrexTypes import py_object_type, error_type from .Symtab import (ModuleScope, LocalScope, ClosureScope, - StructOrUnionScope, PyClassScope, CppClassScope, TemplateScope) + StructOrUnionScope, PyClassScope, CppClassScope, TemplateScope) from .Code import UtilityCode -from .StringEncoding import EncodedString -from . import Future +from .StringEncoding import EncodedString +from . import Future from . import Options from . import DebugFlags from .Pythran import has_np_pythran, pythran_type, is_pythran_buffer -from ..Utils import add_metaclass +from ..Utils import add_metaclass -if sys.version_info[0] >= 3: - _py_int_types = int -else: - _py_int_types = (int, long) +if sys.version_info[0] >= 3: + _py_int_types = int +else: + _py_int_types = (int, long) + - def relative_position(pos): return (pos[0].get_filenametable_entry(), pos[1]) @@ -69,25 +69,25 @@ def embed_position(pos, docstring): def analyse_type_annotation(annotation, env, assigned_value=None): - base_type = None + base_type = None is_ambiguous = False - explicit_pytype = explicit_ctype = False - if annotation.is_dict_literal: + explicit_pytype = explicit_ctype = False + if annotation.is_dict_literal: warning(annotation.pos, "Dicts should no longer be used as type annotations. Use 'cython.int' etc. directly.") - for name, value in annotation.key_value_pairs: - if not name.is_string_literal: - continue - if name.value in ('type', b'type'): - explicit_pytype = True - if not explicit_ctype: - annotation = value - elif name.value in ('ctype', b'ctype'): - explicit_ctype = True - annotation = value - if explicit_pytype and explicit_ctype: - warning(annotation.pos, "Duplicate type declarations found in signature annotation") - arg_type = annotation.analyse_as_type(env) + for name, value in annotation.key_value_pairs: + if not name.is_string_literal: + continue + if name.value in ('type', b'type'): + explicit_pytype = True + if not explicit_ctype: + annotation = value + elif name.value in ('ctype', b'ctype'): + explicit_ctype = True + annotation = value + if explicit_pytype and explicit_ctype: + warning(annotation.pos, "Duplicate type declarations found in signature annotation") + arg_type = annotation.analyse_as_type(env) if annotation.is_name and not annotation.cython_attribute and annotation.name in ('int', 'long', 'float'): # Map builtin numeric Python types to C types in safe cases. if assigned_value is not None and arg_type is not None and not arg_type.is_pyobject: @@ -102,19 +102,19 @@ def analyse_type_annotation(annotation, env, assigned_value=None): elif arg_type is not None and annotation.is_string_literal: warning(annotation.pos, "Strings should no longer be used for type declarations. Use 'cython.int' etc. directly.") - if arg_type is not None: - if explicit_pytype and not explicit_ctype and not arg_type.is_pyobject: - warning(annotation.pos, - "Python type declaration in signature annotation does not refer to a Python type") - base_type = CAnalysedBaseTypeNode( - annotation.pos, type=arg_type, is_arg=True) + if arg_type is not None: + if explicit_pytype and not explicit_ctype and not arg_type.is_pyobject: + warning(annotation.pos, + "Python type declaration in signature annotation does not refer to a Python type") + base_type = CAnalysedBaseTypeNode( + annotation.pos, type=arg_type, is_arg=True) elif is_ambiguous: warning(annotation.pos, "Ambiguous types in annotation, ignoring") - else: + else: warning(annotation.pos, "Unknown type declaration in annotation, ignoring") - return base_type, arg_type - - + return base_type, arg_type + + def write_func_call(func, codewriter_class): def f(*args, **kwds): if len(args) > 1 and isinstance(args[1], codewriter_class): @@ -122,10 +122,10 @@ def write_func_call(func, codewriter_class): # but only if new code is generated node, code = args[:2] marker = ' /* %s -> %s.%s %s */' % ( - ' ' * code.call_level, - node.__class__.__name__, - func.__name__, - node.pos[1:]) + ' ' * code.call_level, + node.__class__.__name__, + func.__name__, + node.pos[1:]) pristine = code.buffer.stream.tell() code.putln(marker) start = code.buffer.stream.tell() @@ -133,10 +133,10 @@ def write_func_call(func, codewriter_class): res = func(*args, **kwds) code.call_level -= 4 if start == code.buffer.stream.tell(): - # no code written => undo writing marker - code.buffer.stream.truncate(pristine) + # no code written => undo writing marker + code.buffer.stream.truncate(pristine) else: - marker = marker.replace('->', '<-', 1) + marker = marker.replace('->', '<-', 1) code.putln(marker) return res else: @@ -170,7 +170,7 @@ class CheckAnalysers(type): def call(*args, **kwargs): retval = func(*args, **kwargs) if retval is None: - print('%s %s %s' % (name, args, kwargs)) + print('%s %s %s' % (name, args, kwargs)) return retval return call @@ -181,14 +181,14 @@ class CheckAnalysers(type): return super(CheckAnalysers, cls).__new__(cls, name, bases, attrs) -def _with_metaclass(cls): - if DebugFlags.debug_trace_code_generation: - return add_metaclass(VerboseCodeWriter)(cls) - #return add_metaclass(CheckAnalysers)(cls) - return cls - - -@_with_metaclass +def _with_metaclass(cls): + if DebugFlags.debug_trace_code_generation: + return add_metaclass(VerboseCodeWriter)(cls) + #return add_metaclass(CheckAnalysers)(cls) + return cls + + +@_with_metaclass class Node(object): # pos (string, int, int) Source file position # is_name boolean Is a NameNode @@ -199,7 +199,7 @@ class Node(object): is_nonecheck = 0 is_literal = 0 is_terminator = 0 - is_wrapper = False # is a DefNode wrapper for a C function + is_wrapper = False # is a DefNode wrapper for a C function temps = None # All descendants should set child_attrs to a list of the attributes @@ -207,9 +207,9 @@ class Node(object): # can either contain a single node or a list of nodes. See Visitor.py. child_attrs = None - # Subset of attributes that are evaluated in the outer scope (e.g. function default arguments). - outer_attrs = None - + # Subset of attributes that are evaluated in the outer scope (e.g. function default arguments). + outer_attrs = None + cf_state = None # This may be an additional (or 'actual') type that will be checked when @@ -225,7 +225,7 @@ class Node(object): gil_message = "Operation" nogil_check = None - in_nogil_context = False # For use only during code generation. + in_nogil_context = False # For use only during code generation. def gil_error(self, env=None): error(self.pos, "%s not allowed without gil" % self.gil_message) @@ -349,9 +349,9 @@ class Node(object): if not self.pos: return u'' source_desc, line, col = self.pos - contents = source_desc.get_lines(encoding='ASCII', error_handling='ignore') + contents = source_desc.get_lines(encoding='ASCII', error_handling='ignore') # line numbers start at 1 - lines = contents[max(0, line-3):line] + lines = contents[max(0, line-3):line] current = lines[-1] if mark_column: current = current[:col] + marker + current[col:] @@ -420,10 +420,10 @@ class StatListNode(Node): child_attrs = ["stats"] - @staticmethod + @staticmethod def create_analysed(pos, env, *args, **kw): node = StatListNode(pos, *args, **kw) - return node # No node-specific analysis needed + return node # No node-specific analysis needed def analyse_declarations(self, env): #print "StatListNode.analyse_declarations" ### @@ -432,8 +432,8 @@ class StatListNode(Node): def analyse_expressions(self, env): #print "StatListNode.analyse_expressions" ### - self.stats = [stat.analyse_expressions(env) - for stat in self.stats] + self.stats = [stat.analyse_expressions(env) + for stat in self.stats] return self def generate_function_definitions(self, env, code): @@ -529,7 +529,7 @@ class CDeclaratorNode(Node): # Only C++ functions have templates. return None - + class CNameDeclaratorNode(CDeclaratorNode): # name string The Cython name being declared # cname string or None C name, if specified @@ -556,37 +556,37 @@ class CNameDeclaratorNode(CDeclaratorNode): self.type = base_type return self, base_type - + class CPtrDeclaratorNode(CDeclaratorNode): # base CDeclaratorNode child_attrs = ["base"] - def analyse_templates(self): - return self.base.analyse_templates() - + def analyse_templates(self): + return self.base.analyse_templates() + def analyse(self, base_type, env, nonempty=0, visibility=None, in_pxd=False): if base_type.is_pyobject: - error(self.pos, "Pointer base type cannot be a Python object") + error(self.pos, "Pointer base type cannot be a Python object") ptr_type = PyrexTypes.c_ptr_type(base_type) return self.base.analyse(ptr_type, env, nonempty=nonempty, visibility=visibility, in_pxd=in_pxd) - + class CReferenceDeclaratorNode(CDeclaratorNode): # base CDeclaratorNode child_attrs = ["base"] - def analyse_templates(self): - return self.base.analyse_templates() - + def analyse_templates(self): + return self.base.analyse_templates() + def analyse(self, base_type, env, nonempty=0, visibility=None, in_pxd=False): if base_type.is_pyobject: - error(self.pos, "Reference base type cannot be a Python object") + error(self.pos, "Reference base type cannot be a Python object") ref_type = PyrexTypes.c_ref_type(base_type) return self.base.analyse(ref_type, env, nonempty=nonempty, visibility=visibility, in_pxd=in_pxd) - + class CArrayDeclaratorNode(CDeclaratorNode): # base CDeclaratorNode # dimension ExprNode @@ -594,7 +594,7 @@ class CArrayDeclaratorNode(CDeclaratorNode): child_attrs = ["base", "dimension"] def analyse(self, base_type, env, nonempty=0, visibility=None, in_pxd=False): - if (base_type.is_cpp_class and base_type.is_template_type()) or base_type.is_cfunction: + if (base_type.is_cpp_class and base_type.is_template_type()) or base_type.is_cfunction: from .ExprNodes import TupleNode if isinstance(self.dimension, TupleNode): args = self.dimension.args @@ -622,11 +622,11 @@ class CArrayDeclaratorNode(CDeclaratorNode): else: size = None if not base_type.is_complete(): - error(self.pos, "Array element type '%s' is incomplete" % base_type) + error(self.pos, "Array element type '%s' is incomplete" % base_type) if base_type.is_pyobject: - error(self.pos, "Array element cannot be a Python object") + error(self.pos, "Array element cannot be a Python object") if base_type.is_cfunction: - error(self.pos, "Array element cannot be a function") + error(self.pos, "Array element cannot be a function") array_type = PyrexTypes.c_array_type(base_type, size) return self.base.analyse(array_type, env, nonempty=nonempty, visibility=visibility, in_pxd=in_pxd) @@ -672,15 +672,15 @@ class CFuncDeclaratorNode(CDeclaratorNode): return None def analyse(self, return_type, env, nonempty=0, directive_locals=None, visibility=None, in_pxd=False): - if directive_locals is None: - directive_locals = {} + if directive_locals is None: + directive_locals = {} if nonempty: nonempty -= 1 func_type_args = [] for i, arg_node in enumerate(self.args): name_declarator, type = arg_node.analyse( - env, nonempty=nonempty, - is_self_arg=(i == 0 and env.is_c_class_scope and 'staticmethod' not in env.directives)) + env, nonempty=nonempty, + is_self_arg=(i == 0 and env.is_c_class_scope and 'staticmethod' not in env.directives)) name = name_declarator.name if name in directive_locals: type_node = directive_locals[name] @@ -694,8 +694,8 @@ class CFuncDeclaratorNode(CDeclaratorNode): else: type = other_type if name_declarator.cname: - error(self.pos, "Function argument cannot have C name specification") - if i == 0 and env.is_c_class_scope and type.is_unspecified: + error(self.pos, "Function argument cannot have C name specification") + if i == 0 and env.is_c_class_scope and type.is_unspecified: # fix the type of self type = env.parent_type # Turn *[] argument into ** @@ -721,7 +721,7 @@ class CFuncDeclaratorNode(CDeclaratorNode): if (return_type.is_pyobject and (self.exception_value or self.exception_check) and self.exception_check != '+'): - error(self.pos, "Exception clause not allowed for function returning Python object") + error(self.pos, "Exception clause not allowed for function returning Python object") else: if self.exception_value is None and self.exception_check and self.exception_check != '+': # Use an explicit exception return value to speed up exception checks. @@ -741,11 +741,11 @@ class CFuncDeclaratorNode(CDeclaratorNode): and not exc_val_type.is_pyobject and not (exc_val_type.is_cfunction and not exc_val_type.return_type.is_pyobject - and not exc_val_type.args) - and not (exc_val_type == PyrexTypes.c_char_type - and self.exception_value.value == '*')): + and not exc_val_type.args) + and not (exc_val_type == PyrexTypes.c_char_type + and self.exception_value.value == '*')): error(self.exception_value.pos, - "Exception value must be a Python exception or cdef function with no arguments or *.") + "Exception value must be a Python exception or cdef function with no arguments or *.") exc_val = self.exception_value else: self.exception_value = self.exception_value.coerce_to( @@ -760,15 +760,15 @@ class CFuncDeclaratorNode(CDeclaratorNode): "Exception value incompatible with function return type") exc_check = self.exception_check if return_type.is_cfunction: - error(self.pos, "Function cannot return a function") + error(self.pos, "Function cannot return a function") func_type = PyrexTypes.CFuncType( return_type, func_type_args, self.has_varargs, - optional_arg_count=self.optional_arg_count, - exception_value=exc_val, exception_check=exc_check, - calling_convention=self.base.calling_convention, - nogil=self.nogil, with_gil=self.with_gil, is_overridable=self.overridable, - is_const_method=self.is_const_method, - templates=self.templates) + optional_arg_count=self.optional_arg_count, + exception_value=exc_val, exception_check=exc_check, + calling_convention=self.base.calling_convention, + nogil=self.nogil, with_gil=self.with_gil, is_overridable=self.overridable, + is_const_method=self.is_const_method, + templates=self.templates) if self.optional_arg_count: if func_type.is_fused: @@ -802,7 +802,7 @@ class CFuncDeclaratorNode(CDeclaratorNode): arg_count_member = '%sn' % Naming.pyrex_prefix scope.declare_var(arg_count_member, PyrexTypes.c_int_type, self.pos) - for arg in func_type.args[len(func_type.args) - self.optional_arg_count:]: + for arg in func_type.args[len(func_type.args) - self.optional_arg_count:]: scope.declare_var(arg.name, arg.type, arg.pos, allow_pyobject=True, allow_memoryview=True) struct_cname = env.mangle(Naming.opt_arg_prefix, self.base.name) @@ -811,12 +811,12 @@ class CFuncDeclaratorNode(CDeclaratorNode): struct_cname = PyrexTypes.get_fused_cname(fused_cname, struct_cname) op_args_struct = env.global_scope().declare_struct_or_union( - name=struct_cname, - kind='struct', - scope=scope, - typedef_flag=0, - pos=self.pos, - cname=struct_cname) + name=struct_cname, + kind='struct', + scope=scope, + typedef_flag=0, + pos=self.pos, + cname=struct_cname) op_args_struct.defined_in_pxd = 1 op_args_struct.used = 1 @@ -854,7 +854,7 @@ class CArgDeclNode(Node): # is_dynamic boolean Non-literal arg stored inside CyFunction child_attrs = ["base_type", "declarator", "default", "annotation"] - outer_attrs = ["default", "annotation"] + outer_attrs = ["default", "annotation"] is_self_arg = 0 is_type_arg = 0 @@ -868,7 +868,7 @@ class CArgDeclNode(Node): annotation = None is_dynamic = 0 - def analyse(self, env, nonempty=0, is_self_arg=False): + def analyse(self, env, nonempty=0, is_self_arg=False): if is_self_arg: self.base_type.is_self_arg = self.is_self_arg = True if self.type is None: @@ -878,7 +878,7 @@ class CArgDeclNode(Node): if self.base_type.is_basic_c_type: # char, short, long called "int" type = self.base_type.analyse(env, could_be_name=True) - arg_name = type.empty_declaration_code() + arg_name = type.empty_declaration_code() else: arg_name = self.base_type.name self.declarator.name = EncodedString(arg_name) @@ -919,8 +919,8 @@ class CArgDeclNode(Node): if not annotation: return None base_type, arg_type = analyse_type_annotation(annotation, env, assigned_value=self.default) - if base_type is not None: - self.base_type = base_type + if base_type is not None: + self.base_type = base_type return arg_type def calculate_default_value_code(self, code): @@ -937,7 +937,7 @@ class CArgDeclNode(Node): if self.default: self.default.annotate(code) - def generate_assignment_code(self, code, target=None, overloaded_assignment=False): + def generate_assignment_code(self, code, target=None, overloaded_assignment=False): default = self.default if default is None or default.is_literal: return @@ -945,7 +945,7 @@ class CArgDeclNode(Node): target = self.calculate_default_value_code(code) default.generate_evaluation_code(code) default.make_owned_reference(code) - result = default.result() if overloaded_assignment else default.result_as(self.type) + result = default.result() if overloaded_assignment else default.result_as(self.type) code.putln("%s = %s;" % (target, result)) if self.type.is_pyobject: code.put_giveref(default.result()) @@ -964,16 +964,16 @@ class CBaseTypeNode(Node): def analyse_as_type(self, env): return self.analyse(env) - + class CAnalysedBaseTypeNode(Node): # type type child_attrs = [] - def analyse(self, env, could_be_name=False): + def analyse(self, env, could_be_name=False): return self.type - + class CSimpleBaseTypeNode(CBaseTypeNode): # name string # module_path [string] Qualifying name components @@ -990,7 +990,7 @@ class CSimpleBaseTypeNode(CBaseTypeNode): is_basic_c_type = False complex = False - def analyse(self, env, could_be_name=False): + def analyse(self, env, could_be_name=False): # Return type descriptor. #print "CSimpleBaseTypeNode.analyse: is_self_arg =", self.is_self_arg ### type = None @@ -1073,7 +1073,7 @@ class MemoryViewSliceTypeNode(CBaseTypeNode): name = 'memoryview' child_attrs = ['base_type_node', 'axes'] - def analyse(self, env, could_be_name=False): + def analyse(self, env, could_be_name=False): base_type = self.base_type_node.analyse(env) if base_type.is_error: return base_type @@ -1082,7 +1082,7 @@ class MemoryViewSliceTypeNode(CBaseTypeNode): try: axes_specs = MemoryView.get_axes_specs(env, self.axes) - except CompileError as e: + except CompileError as e: error(e.position, e.message_only) self.type = PyrexTypes.ErrorType() return self.type @@ -1091,7 +1091,7 @@ class MemoryViewSliceTypeNode(CBaseTypeNode): self.type = error_type else: self.type = PyrexTypes.MemoryViewSliceType(base_type, axes_specs) - self.type.validate_memslice_dtype(self.pos) + self.type.validate_memslice_dtype(self.pos) self.use_memview_utilities(env) return self.type @@ -1109,7 +1109,7 @@ class CNestedBaseTypeNode(CBaseTypeNode): child_attrs = ['base_type'] - def analyse(self, env, could_be_name=None): + def analyse(self, env, could_be_name=None): base_type = self.base_type.analyse(env) if base_type is PyrexTypes.error_type: return PyrexTypes.error_type @@ -1139,12 +1139,12 @@ class TemplatedTypeNode(CBaseTypeNode): name = None - def analyse(self, env, could_be_name=False, base_type=None): + def analyse(self, env, could_be_name=False, base_type=None): if base_type is None: base_type = self.base_type_node.analyse(env) if base_type.is_error: return base_type - if base_type.is_cpp_class and base_type.is_template_type(): + if base_type.is_cpp_class and base_type.is_template_type(): # Templated class if self.keyword_args and self.keyword_args.key_value_pairs: error(self.pos, "c++ templates cannot take keyword arguments") @@ -1172,8 +1172,8 @@ class TemplatedTypeNode(CBaseTypeNode): if sys.version_info[0] < 3: # Py 2.x enforces byte strings as keyword arguments ... - options = dict([(name.encode('ASCII'), value) - for name, value in options.items()]) + options = dict([(name.encode('ASCII'), value) + for name, value in options.items()]) self.type = PyrexTypes.BufferType(base_type, **options) if has_np_pythran(env) and is_pythran_buffer(self.type): @@ -1192,10 +1192,10 @@ class TemplatedTypeNode(CBaseTypeNode): dimension = None else: dimension = self.positional_args[0] - self.array_declarator = CArrayDeclaratorNode( - self.pos, - base=empty_declarator, - dimension=dimension) + self.array_declarator = CArrayDeclaratorNode( + self.pos, + base=empty_declarator, + dimension=dimension) self.type = self.array_declarator.analyse(base_type, env)[1] if self.type.is_fused and env.fused_to_specific: @@ -1203,37 +1203,37 @@ class TemplatedTypeNode(CBaseTypeNode): return self.type - + class CComplexBaseTypeNode(CBaseTypeNode): # base_type CBaseTypeNode # declarator CDeclaratorNode child_attrs = ["base_type", "declarator"] - def analyse(self, env, could_be_name=False): + def analyse(self, env, could_be_name=False): base = self.base_type.analyse(env, could_be_name) _, type = self.declarator.analyse(base, env) return type -class CTupleBaseTypeNode(CBaseTypeNode): - # components [CBaseTypeNode] - - child_attrs = ["components"] - - def analyse(self, env, could_be_name=False): - component_types = [] - for c in self.components: - type = c.analyse(env) - if type.is_pyobject: - error(c.pos, "Tuple types can't (yet) contain Python objects.") - return error_type - component_types.append(type) - entry = env.declare_tuple_type(self.pos, component_types) - entry.used = True - return entry.type - - +class CTupleBaseTypeNode(CBaseTypeNode): + # components [CBaseTypeNode] + + child_attrs = ["components"] + + def analyse(self, env, could_be_name=False): + component_types = [] + for c in self.components: + type = c.analyse(env) + if type.is_pyobject: + error(c.pos, "Tuple types can't (yet) contain Python objects.") + return error_type + component_types.append(type) + entry = env.declare_tuple_type(self.pos, component_types) + entry.used = True + return entry.type + + class FusedTypeNode(CBaseTypeNode): """ Represents a fused type in a ctypedef statement: @@ -1253,7 +1253,7 @@ class FusedTypeNode(CBaseTypeNode): # Omit the typedef declaration that self.declarator would produce entry.in_cinclude = True - def analyse(self, env, could_be_name=False): + def analyse(self, env, could_be_name=False): types = [] for type_node in self.types: type = type_node.analyse_as_type(env) @@ -1278,7 +1278,7 @@ class CConstTypeNode(CBaseTypeNode): child_attrs = ["base_type"] - def analyse(self, env, could_be_name=False): + def analyse(self, env, could_be_name=False): base = self.base_type.analyse(env, could_be_name) if base.is_pyobject: error(self.pos, @@ -1305,7 +1305,7 @@ class CVarDefNode(StatNode): decorators = None directive_locals = None - def analyse_declarations(self, env, dest_scope=None): + def analyse_declarations(self, env, dest_scope=None): if self.directive_locals is None: self.directive_locals = {} if not dest_scope: @@ -1339,18 +1339,18 @@ class CVarDefNode(StatNode): for declarator in self.declarators: if (len(self.declarators) > 1 - and not isinstance(declarator, CNameDeclaratorNode) - and env.directives['warn.multiple_declarators']): - warning( - declarator.pos, - "Non-trivial type declarators in shared declaration (e.g. mix of pointers and values). " + and not isinstance(declarator, CNameDeclaratorNode) + and env.directives['warn.multiple_declarators']): + warning( + declarator.pos, + "Non-trivial type declarators in shared declaration (e.g. mix of pointers and values). " "Each pointer declaration should be on its own line.", 1) - create_extern_wrapper = (self.overridable - and self.visibility == 'extern' - and env.is_module_scope) - if create_extern_wrapper: - declarator.overridable = False + create_extern_wrapper = (self.overridable + and self.visibility == 'extern' + and env.is_module_scope) + if create_extern_wrapper: + declarator.overridable = False if isinstance(declarator, CFuncDeclaratorNode): name_declarator, type = declarator.analyse( base_type, env, directive_locals=self.directive_locals, visibility=visibility, in_pxd=self.in_pxd) @@ -1359,9 +1359,9 @@ class CVarDefNode(StatNode): base_type, env, visibility=visibility, in_pxd=self.in_pxd) if not type.is_complete(): if not (self.visibility == 'extern' and type.is_array or type.is_memoryviewslice): - error(declarator.pos, "Variable type '%s' is incomplete" % type) + error(declarator.pos, "Variable type '%s' is incomplete" % type) if self.visibility == 'extern' and type.is_pyobject: - error(declarator.pos, "Python object cannot be declared extern") + error(declarator.pos, "Python object cannot be declared extern") name = name_declarator.name cname = name_declarator.cname if name == '': @@ -1370,27 +1370,27 @@ class CVarDefNode(StatNode): if type.is_reference and self.visibility != 'extern': error(declarator.pos, "C++ references cannot be declared; use a pointer instead") if type.is_cfunction: - if 'staticmethod' in env.directives: - type.is_static_method = True - self.entry = dest_scope.declare_cfunction( - name, type, declarator.pos, - cname=cname, visibility=self.visibility, in_pxd=self.in_pxd, - api=self.api, modifiers=self.modifiers, overridable=self.overridable) + if 'staticmethod' in env.directives: + type.is_static_method = True + self.entry = dest_scope.declare_cfunction( + name, type, declarator.pos, + cname=cname, visibility=self.visibility, in_pxd=self.in_pxd, + api=self.api, modifiers=self.modifiers, overridable=self.overridable) if self.entry is not None: self.entry.directive_locals = copy.copy(self.directive_locals) - if create_extern_wrapper: - self.entry.type.create_to_py_utility_code(env) - self.entry.create_wrapper = True + if create_extern_wrapper: + self.entry.type.create_to_py_utility_code(env) + self.entry.create_wrapper = True else: if self.overridable: warning(self.pos, "cpdef variables will not be supported in Cython 3; " "currently they are no different from cdef variables", 2) if self.directive_locals: error(self.pos, "Decorators can only be followed by functions") - self.entry = dest_scope.declare_var( - name, type, declarator.pos, - cname=cname, visibility=visibility, in_pxd=self.in_pxd, - api=self.api, is_cdef=1) + self.entry = dest_scope.declare_var( + name, type, declarator.pos, + cname=cname, visibility=visibility, in_pxd=self.in_pxd, + api=self.api, is_cdef=1) if Options.docstrings: self.entry.doc = embed_position(self.pos, self.doc) @@ -1412,8 +1412,8 @@ class CStructOrUnionDefNode(StatNode): def declare(self, env, scope=None): self.entry = env.declare_struct_or_union( self.name, self.kind, scope, self.typedef_flag, self.pos, - self.cname, visibility=self.visibility, api=self.api, - packed=self.packed) + self.cname, visibility=self.visibility, api=self.api, + packed=self.packed) def analyse_declarations(self, env): scope = None @@ -1449,7 +1449,7 @@ class CppClassNode(CStructOrUnionDefNode, BlockNode): # attributes [CVarDefNode] or None # entry Entry # base_classes [CBaseTypeNode] - # templates [(string, bool)] or None + # templates [(string, bool)] or None # decorators [DecoratorNode] or None decorators = None @@ -1458,25 +1458,25 @@ class CppClassNode(CStructOrUnionDefNode, BlockNode): if self.templates is None: template_types = None else: - template_types = [PyrexTypes.TemplatePlaceholderType(template_name, not required) - for template_name, required in self.templates] - num_optional_templates = sum(not required for _, required in self.templates) - if num_optional_templates and not all(required for _, required in self.templates[:-num_optional_templates]): - error(self.pos, "Required template parameters must precede optional template parameters.") + template_types = [PyrexTypes.TemplatePlaceholderType(template_name, not required) + for template_name, required in self.templates] + num_optional_templates = sum(not required for _, required in self.templates) + if num_optional_templates and not all(required for _, required in self.templates[:-num_optional_templates]): + error(self.pos, "Required template parameters must precede optional template parameters.") self.entry = env.declare_cpp_class( - self.name, None, self.pos, self.cname, - base_classes=[], visibility=self.visibility, templates=template_types) + self.name, None, self.pos, self.cname, + base_classes=[], visibility=self.visibility, templates=template_types) def analyse_declarations(self, env): - if self.templates is None: - template_types = template_names = None - else: - template_names = [template_name for template_name, _ in self.templates] - template_types = [PyrexTypes.TemplatePlaceholderType(template_name, not required) - for template_name, required in self.templates] + if self.templates is None: + template_types = template_names = None + else: + template_names = [template_name for template_name, _ in self.templates] + template_types = [PyrexTypes.TemplatePlaceholderType(template_name, not required) + for template_name, required in self.templates] scope = None if self.attributes is not None: - scope = CppClassScope(self.name, env, templates=template_names) + scope = CppClassScope(self.name, env, templates=template_names) def base_ok(base_class): if base_class.is_cpp_class or base_class.is_struct: return True @@ -1485,7 +1485,7 @@ class CppClassNode(CStructOrUnionDefNode, BlockNode): base_class_types = filter(base_ok, [b.analyse(scope or env) for b in self.base_classes]) self.entry = env.declare_cpp_class( self.name, scope, self.pos, - self.cname, base_class_types, visibility=self.visibility, templates=template_types) + self.cname, base_class_types, visibility=self.visibility, templates=template_types) if self.entry is None: return self.entry.is_cpp_class = 1 @@ -1503,14 +1503,14 @@ class CppClassNode(CStructOrUnionDefNode, BlockNode): if self.in_pxd and not env.in_cinclude: self.entry.defined_in_pxd = 1 for attr in self.attributes: - declare = getattr(attr, 'declare', None) - if declare: - attr.declare(scope) + declare = getattr(attr, 'declare', None) + if declare: + attr.declare(scope) attr.analyse_declarations(scope) for func in func_attributes(self.attributes): defined_funcs.append(func) if self.templates is not None: - func.template_declaration = "template <typename %s>" % ", typename ".join(template_names) + func.template_declaration = "template <typename %s>" % ", typename ".join(template_names) self.body = StatListNode(self.pos, stats=defined_funcs) self.scope = scope @@ -1542,11 +1542,11 @@ class CEnumDefNode(StatNode): child_attrs = ["items"] def declare(self, env): - self.entry = env.declare_enum( - self.name, self.pos, - cname=self.cname, typedef_flag=self.typedef_flag, - visibility=self.visibility, api=self.api, - create_wrapper=self.create_wrapper) + self.entry = env.declare_enum( + self.name, self.pos, + cname=self.cname, typedef_flag=self.typedef_flag, + visibility=self.visibility, api=self.api, + create_wrapper=self.create_wrapper) def analyse_declarations(self, env): if self.items is not None: @@ -1560,19 +1560,19 @@ class CEnumDefNode(StatNode): def generate_execution_code(self, code): if self.visibility == 'public' or self.api: - code.mark_pos(self.pos) + code.mark_pos(self.pos) temp = code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=True) for item in self.entry.enum_values: code.putln("%s = PyInt_FromLong(%s); %s" % ( - temp, - item.cname, - code.error_goto_if_null(temp, item.pos))) + temp, + item.cname, + code.error_goto_if_null(temp, item.pos))) code.put_gotref(temp) code.putln('if (PyDict_SetItemString(%s, "%s", %s) < 0) %s' % ( - Naming.moddict_cname, - item.name, - temp, - code.error_goto(item.pos))) + Naming.moddict_cname, + item.name, + temp, + code.error_goto(item.pos))) code.put_decref_clear(temp, PyrexTypes.py_object_type) code.funcstate.release_temp(temp) @@ -1590,14 +1590,14 @@ class CEnumDefItemNode(StatNode): if not self.value.type.is_int: self.value = self.value.coerce_to(PyrexTypes.c_int_type, env) self.value = self.value.analyse_const_expression(env) - entry = env.declare_const( - self.name, enum_entry.type, - self.value, self.pos, cname=self.cname, - visibility=enum_entry.visibility, api=enum_entry.api, - create_wrapper=enum_entry.create_wrapper and enum_entry.name is None) + entry = env.declare_const( + self.name, enum_entry.type, + self.value, self.pos, cname=self.cname, + visibility=enum_entry.visibility, api=enum_entry.api, + create_wrapper=enum_entry.create_wrapper and enum_entry.name is None) enum_entry.enum_values.append(entry) - if enum_entry.name: - enum_entry.type.values.append(entry.name) + if enum_entry.name: + enum_entry.type.values.append(entry.name) class CTypeDefNode(StatNode): @@ -1616,9 +1616,9 @@ class CTypeDefNode(StatNode): name = name_declarator.name cname = name_declarator.cname - entry = env.declare_typedef( - name, type, self.pos, - cname=cname, visibility=self.visibility, api=self.api) + entry = env.declare_typedef( + name, type, self.pos, + cname=cname, visibility=self.visibility, api=self.api) if type.is_fused: entry.in_cinclude = True @@ -1644,11 +1644,11 @@ class FuncDefNode(StatNode, BlockNode): # pymethdef_required boolean Force Python method struct generation # directive_locals { string : ExprNode } locals defined by cython.locals(...) # directive_returns [ExprNode] type defined by cython.returns(...) - # star_arg PyArgDeclNode or None * argument - # starstar_arg PyArgDeclNode or None ** argument - # - # is_async_def boolean is a Coroutine function - # + # star_arg PyArgDeclNode or None * argument + # starstar_arg PyArgDeclNode or None ** argument + # + # is_async_def boolean is a Coroutine function + # # has_fused_arguments boolean # Whether this cdef function has fused parameters. This is needed # by AnalyseDeclarationsTransform, so it can replace CFuncDefNodes @@ -1660,13 +1660,13 @@ class FuncDefNode(StatNode, BlockNode): pymethdef_required = False is_generator = False is_generator_body = False - is_async_def = False + is_async_def = False modifiers = [] has_fused_arguments = False star_arg = None starstar_arg = None is_cyfunction = False - code_object = None + code_object = None def analyse_default_values(self, env): default_seen = 0 @@ -1677,7 +1677,7 @@ class FuncDefNode(StatNode, BlockNode): arg.default = arg.default.analyse_types(env) arg.default = arg.default.coerce_to(arg.type, env) else: - error(arg.pos, "This argument cannot have a default value") + error(arg.pos, "This argument cannot have a default value") arg.default = None elif arg.kw_only: default_seen = 1 @@ -1692,11 +1692,11 @@ class FuncDefNode(StatNode, BlockNode): annotation = annotation.analyse_types(env) return annotation - def analyse_annotations(self, env): - for arg in self.args: - if arg.annotation: + def analyse_annotations(self, env): + for arg in self.args: + if arg.annotation: arg.annotation = self.analyse_annotation(env, arg.annotation) - + def align_argument_type(self, env, arg): # @cython.locals() directive_locals = self.directive_locals @@ -1704,7 +1704,7 @@ class FuncDefNode(StatNode, BlockNode): if arg.name in directive_locals: type_node = directive_locals[arg.name] other_type = type_node.analyse_as_type(env) - elif isinstance(arg, CArgDeclNode) and arg.annotation and env.directives['annotation_typing']: + elif isinstance(arg, CArgDeclNode) and arg.annotation and env.directives['annotation_typing']: type_node = arg.annotation other_type = arg.inject_type_from_annotations(env) if other_type is None: @@ -1713,7 +1713,7 @@ class FuncDefNode(StatNode, BlockNode): return arg if other_type is None: error(type_node.pos, "Not a type") - elif orig_type is not py_object_type and not orig_type.same_as(other_type): + elif orig_type is not py_object_type and not orig_type.same_as(other_type): error(arg.base_type.pos, "Signature does not agree with previous declaration") error(type_node.pos, "Previous declaration here") else: @@ -1729,8 +1729,8 @@ class FuncDefNode(StatNode, BlockNode): genv = genv.outer_scope if self.needs_closure: lenv = ClosureScope(name=self.entry.name, - outer_scope=genv, - parent_scope=env, + outer_scope=genv, + parent_scope=env, scope_name=self.entry.cname) else: lenv = LocalScope(name=self.entry.name, @@ -1782,9 +1782,9 @@ class FuncDefNode(StatNode, BlockNode): UtilityCode.load_cached("Profile", "Profile.c")) # Generate C code for header and body of function - code.enter_cfunc_scope(lenv) + code.enter_cfunc_scope(lenv) code.return_from_error_cleanup_label = code.new_label() - code.funcstate.gil_owned = not lenv.nogil + code.funcstate.gil_owned = not lenv.nogil # ----- Top-level constants used by this function code.mark_pos(self.pos) @@ -1798,9 +1798,9 @@ class FuncDefNode(StatNode, BlockNode): with_pymethdef = (self.needs_assignment_synthesis(env, code) or self.pymethdef_required) if self.py_func: - self.py_func.generate_function_header( - code, with_pymethdef=with_pymethdef, proto_only=True) - self.generate_function_header(code, with_pymethdef=with_pymethdef) + self.py_func.generate_function_header( + code, with_pymethdef=with_pymethdef, proto_only=True) + self.generate_function_header(code, with_pymethdef=with_pymethdef) # ----- Local variable declarations # Find function scope cenv = env @@ -1829,9 +1829,9 @@ class FuncDefNode(StatNode, BlockNode): elif self.return_type.is_memoryviewslice: init = ' = ' + MemoryView.memslice_entry_init - code.putln("%s%s;" % ( - self.return_type.declaration_code(Naming.retval_cname), - init)) + code.putln("%s%s;" % ( + self.return_type.declaration_code(Naming.retval_cname), + init)) tempvardecl_code = code.insertion_point() self.generate_keyword_list(code) @@ -1842,39 +1842,39 @@ class FuncDefNode(StatNode, BlockNode): # See if we need to acquire the GIL for variable declarations, or for # refnanny only - # Closures are not currently possible for cdef nogil functions, - # but check them anyway - have_object_args = self.needs_closure or self.needs_outer_scope + # Closures are not currently possible for cdef nogil functions, + # but check them anyway + have_object_args = self.needs_closure or self.needs_outer_scope for arg in lenv.arg_entries: if arg.type.is_pyobject: have_object_args = True break - used_buffer_entries = [entry for entry in lenv.buffer_entries if entry.used] - + used_buffer_entries = [entry for entry in lenv.buffer_entries if entry.used] + acquire_gil_for_var_decls_only = ( - lenv.nogil and lenv.has_with_gil_block and - (have_object_args or used_buffer_entries)) + lenv.nogil and lenv.has_with_gil_block and + (have_object_args or used_buffer_entries)) acquire_gil_for_refnanny_only = ( - lenv.nogil and lenv.has_with_gil_block and not - acquire_gil_for_var_decls_only) + lenv.nogil and lenv.has_with_gil_block and not + acquire_gil_for_var_decls_only) use_refnanny = not lenv.nogil or lenv.has_with_gil_block if acquire_gil or acquire_gil_for_var_decls_only: code.put_ensure_gil() - code.funcstate.gil_owned = True + code.funcstate.gil_owned = True elif lenv.nogil and lenv.has_with_gil_block: code.declare_gilstate() - if profile or linetrace: + if profile or linetrace: if not self.is_generator: # generators are traced when iterated, not at creation tempvardecl_code.put_trace_declarations() code_object = self.code_object.calculate_result_code(code) if self.code_object else None code.put_trace_frame_init(code_object) - + # ----- Special check for getbuffer if is_getbuffer_slot: self.getbuffer_check(code) @@ -1896,31 +1896,31 @@ class FuncDefNode(StatNode, BlockNode): slot_func_cname = '%s->tp_new' % lenv.scope_class.type.typeptr_cname code.putln("%s = (%s)%s(%s, %s, NULL);" % ( Naming.cur_scope_cname, - lenv.scope_class.type.empty_declaration_code(), + lenv.scope_class.type.empty_declaration_code(), slot_func_cname, lenv.scope_class.type.typeptr_cname, Naming.empty_tuple)) code.putln("if (unlikely(!%s)) {" % Naming.cur_scope_cname) - # Scope unconditionally DECREFed on return. - code.putln("%s = %s;" % ( - Naming.cur_scope_cname, + # Scope unconditionally DECREFed on return. + code.putln("%s = %s;" % ( + Naming.cur_scope_cname, lenv.scope_class.type.cast_code("Py_None"))) code.put_incref("Py_None", py_object_type) - code.putln(code.error_goto(self.pos)) - code.putln("} else {") - code.put_gotref(Naming.cur_scope_cname) + code.putln(code.error_goto(self.pos)) + code.putln("} else {") + code.put_gotref(Naming.cur_scope_cname) code.putln("}") # Note that it is unsafe to decref the scope at this point. if self.needs_outer_scope: if self.is_cyfunction: code.putln("%s = (%s) __Pyx_CyFunction_GetClosure(%s);" % ( outer_scope_cname, - cenv.scope_class.type.empty_declaration_code(), + cenv.scope_class.type.empty_declaration_code(), Naming.self_cname)) else: code.putln("%s = (%s) %s;" % ( outer_scope_cname, - cenv.scope_class.type.empty_declaration_code(), + cenv.scope_class.type.empty_declaration_code(), Naming.self_cname)) if lenv.is_passthrough: code.putln("%s = %s;" % (Naming.cur_scope_cname, outer_scope_cname)) @@ -1948,21 +1948,21 @@ class FuncDefNode(StatNode, BlockNode): is_cdef = isinstance(self, CFuncDefNode) for entry in lenv.arg_entries: if entry.type.is_pyobject: - if (acquire_gil or len(entry.cf_assignments) > 1) and not entry.in_closure: + if (acquire_gil or len(entry.cf_assignments) > 1) and not entry.in_closure: code.put_var_incref(entry) # Note: defaults are always incref-ed. For def functions, we # we acquire arguments from object conversion, so we have # new references. If we are a cdef function, we need to # incref our arguments - elif is_cdef and entry.type.is_memoryviewslice and len(entry.cf_assignments) > 1: - code.put_incref_memoryviewslice(entry.cname, have_gil=code.funcstate.gil_owned) + elif is_cdef and entry.type.is_memoryviewslice and len(entry.cf_assignments) > 1: + code.put_incref_memoryviewslice(entry.cname, have_gil=code.funcstate.gil_owned) for entry in lenv.var_entries: - if entry.is_arg and len(entry.cf_assignments) > 1 and not entry.in_closure: - if entry.xdecref_cleanup: - code.put_var_xincref(entry) - else: - code.put_var_incref(entry) + if entry.is_arg and len(entry.cf_assignments) > 1 and not entry.in_closure: + if entry.xdecref_cleanup: + code.put_var_xincref(entry) + else: + code.put_var_incref(entry) # ----- Initialise local buffer auxiliary variables for entry in lenv.var_entries + lenv.arg_entries: @@ -1978,14 +1978,14 @@ class FuncDefNode(StatNode, BlockNode): if acquire_gil_for_var_decls_only: code.put_release_ensured_gil() - code.funcstate.gil_owned = False + code.funcstate.gil_owned = False # ------------------------- # ----- Function body ----- # ------------------------- self.generate_function_body(env, code) - code.mark_pos(self.pos, trace=False) + code.mark_pos(self.pos, trace=False) code.putln("") code.putln("/* function exit code */") @@ -2013,16 +2013,16 @@ class FuncDefNode(StatNode, BlockNode): # Clean up buffers -- this calls a Python function # so need to save and restore error state - buffers_present = len(used_buffer_entries) > 0 - #memslice_entries = [e for e in lenv.entries.values() if e.type.is_memoryviewslice] + buffers_present = len(used_buffer_entries) > 0 + #memslice_entries = [e for e in lenv.entries.values() if e.type.is_memoryviewslice] if buffers_present: code.globalstate.use_utility_code(restore_exception_utility_code) code.putln("{ PyObject *__pyx_type, *__pyx_value, *__pyx_tb;") - code.putln("__Pyx_PyThreadState_declare") - code.putln("__Pyx_PyThreadState_assign") + code.putln("__Pyx_PyThreadState_declare") + code.putln("__Pyx_PyThreadState_assign") code.putln("__Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb);") - for entry in used_buffer_entries: - Buffer.put_release_buffer_code(code, entry) + for entry in used_buffer_entries: + Buffer.put_release_buffer_code(code, entry) #code.putln("%s = 0;" % entry.cname) code.putln("__Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);}") @@ -2051,13 +2051,13 @@ class FuncDefNode(StatNode, BlockNode): warning(self.entry.pos, "Unraisable exception in function '%s'." % self.entry.qualified_name, 0) - code.put_unraisable(self.entry.qualified_name, lenv.nogil) + code.put_unraisable(self.entry.qualified_name, lenv.nogil) default_retval = self.return_type.default_value if err_val is None and default_retval: err_val = default_retval if err_val is not None: - if err_val != Naming.retval_cname: - code.putln("%s = %s;" % (Naming.retval_cname, err_val)) + if err_val != Naming.retval_cname: + code.putln("%s = %s;" % (Naming.retval_cname, err_val)) elif not self.return_type.is_void: code.putln("__Pyx_pretend_to_initialize(&%s);" % Naming.retval_cname) @@ -2072,8 +2072,8 @@ class FuncDefNode(StatNode, BlockNode): # ----- Non-error return cleanup code.put_label(code.return_label) - for entry in used_buffer_entries: - Buffer.put_release_buffer_code(code, entry) + for entry in used_buffer_entries: + Buffer.put_release_buffer_code(code, entry) if is_getbuffer_slot: self.getbuffer_normal_cleanup(code) @@ -2081,13 +2081,13 @@ class FuncDefNode(StatNode, BlockNode): # See if our return value is uninitialized on non-error return # from . import MemoryView # MemoryView.err_if_nogil_initialized_check(self.pos, env) - cond = code.unlikely(self.return_type.error_condition(Naming.retval_cname)) + cond = code.unlikely(self.return_type.error_condition(Naming.retval_cname)) code.putln( 'if (%s) {' % cond) if env.nogil: code.put_ensure_gil() code.putln( - 'PyErr_SetString(PyExc_TypeError, "Memoryview return value is not initialized");') + 'PyErr_SetString(PyExc_TypeError, "Memoryview return value is not initialized");') if env.nogil: code.put_release_ensured_gil() code.putln( @@ -2101,18 +2101,18 @@ class FuncDefNode(StatNode, BlockNode): continue if entry.type.is_memoryviewslice: - code.put_xdecref_memoryviewslice(entry.cname, have_gil=not lenv.nogil) + code.put_xdecref_memoryviewslice(entry.cname, have_gil=not lenv.nogil) elif entry.type.is_pyobject: if not entry.is_arg or len(entry.cf_assignments) > 1: - if entry.xdecref_cleanup: - code.put_var_xdecref(entry) - else: - code.put_var_decref(entry) + if entry.xdecref_cleanup: + code.put_var_xdecref(entry) + else: + code.put_var_decref(entry) # Decref any increfed args for entry in lenv.arg_entries: if entry.type.is_pyobject: - if (acquire_gil or len(entry.cf_assignments) > 1) and not entry.in_closure: + if (acquire_gil or len(entry.cf_assignments) > 1) and not entry.in_closure: code.put_var_decref(entry) elif (entry.type.is_memoryviewslice and (not is_cdef or len(entry.cf_assignments) > 1)): @@ -2137,7 +2137,7 @@ class FuncDefNode(StatNode, BlockNode): # Returning -1 for __hash__ is supposed to signal an error # We do as Python instances and coerce -1 into -2. code.putln("if (unlikely(%s == -1) && !PyErr_Occurred()) %s = -2;" % ( - Naming.retval_cname, Naming.retval_cname)) + Naming.retval_cname, Naming.retval_cname)) if profile or linetrace: code.funcstate.can_trace = False @@ -2157,7 +2157,7 @@ class FuncDefNode(StatNode, BlockNode): if acquire_gil or (lenv.nogil and lenv.has_with_gil_block): # release the GIL (note that with-gil blocks acquire it on exit in their EnsureGILNode) code.put_release_ensured_gil() - code.funcstate.gil_owned = False + code.funcstate.gil_owned = False if not self.return_type.is_void: code.putln("return %s;" % Naming.retval_cname) @@ -2180,7 +2180,7 @@ class FuncDefNode(StatNode, BlockNode): if arg.type.is_void: error(arg.pos, "Invalid use of 'void'") elif not arg.type.is_complete() and not (arg.type.is_array or arg.type.is_memoryviewslice): - error(arg.pos, "Argument type '%s' is incomplete" % arg.type) + error(arg.pos, "Argument type '%s' is incomplete" % arg.type) entry = env.declare_arg(arg.name, arg.type, arg.pos) if arg.annotation: entry.annotation = arg.annotation @@ -2199,10 +2199,10 @@ class FuncDefNode(StatNode, BlockNode): typeptr_cname, arg.accept_none, arg.name, - arg.type.is_builtin_type and arg.type.require_exact, + arg.type.is_builtin_type and arg.type.require_exact, code.error_goto(arg.pos))) else: - error(arg.pos, "Cannot test type of extern C class without type object name specification") + error(arg.pos, "Cannot test type of extern C class without type object name specification") def generate_arg_none_check(self, arg, code): # Generate None check for one argument. @@ -2221,7 +2221,7 @@ class FuncDefNode(StatNode, BlockNode): pass def generate_execution_code(self, code): - code.mark_pos(self.pos) + code.mark_pos(self.pos) # Evaluate and store argument default values for arg in self.args: if not arg.is_dynamic: @@ -2336,16 +2336,16 @@ class CFuncDefNode(FuncDefNode): def unqualified_name(self): return self.entry.name - @property - def code_object(self): - # share the CodeObject with the cpdef wrapper (if available) - return self.py_func.code_object if self.py_func else None - + @property + def code_object(self): + # share the CodeObject with the cpdef wrapper (if available) + return self.py_func.code_object if self.py_func else None + def analyse_declarations(self, env): self.is_c_class_method = env.is_c_class_scope if self.directive_locals is None: self.directive_locals = {} - self.directive_locals.update(env.directives.get('locals', {})) + self.directive_locals.update(env.directives.get('locals', {})) if self.directive_returns is not None: base_type = self.directive_returns.analyse_as_type(env) if base_type is None: @@ -2356,14 +2356,14 @@ class CFuncDefNode(FuncDefNode): self.is_static_method = 'staticmethod' in env.directives and not env.lookup_here('staticmethod') # The 2 here is because we need both function and argument names. if isinstance(self.declarator, CFuncDeclaratorNode): - name_declarator, type = self.declarator.analyse( - base_type, env, nonempty=2 * (self.body is not None), + name_declarator, type = self.declarator.analyse( + base_type, env, nonempty=2 * (self.body is not None), directive_locals=self.directive_locals, visibility=self.visibility) else: - name_declarator, type = self.declarator.analyse( + name_declarator, type = self.declarator.analyse( base_type, env, nonempty=2 * (self.body is not None), visibility=self.visibility) if not type.is_cfunction: - error(self.pos, "Suite attached to non-function declaration") + error(self.pos, "Suite attached to non-function declaration") # Remember the actual type according to the function header # written here, because the type in the symbol table entry # may be different if we're overriding a C method inherited @@ -2380,9 +2380,9 @@ class CFuncDefNode(FuncDefNode): opt_arg_count = self.cfunc_declarator.optional_arg_count if (self.visibility == 'public' or self.api) and opt_arg_count: error(self.cfunc_declarator.pos, - "Function with optional arguments may not be declared public or api") + "Function with optional arguments may not be declared public or api") - if type.exception_check == '+' and self.visibility != 'extern': + if type.exception_check == '+' and self.visibility != 'extern': warning(self.cfunc_declarator.pos, "Only extern functions can throw C++ exceptions.") @@ -2403,7 +2403,7 @@ class CFuncDefNode(FuncDefNode): if type_arg.type.is_buffer or type_arg.type.is_pythran_expr: if self.type.nogil: error(formal_arg.pos, - "Buffer may not be acquired without the GIL. Consider using memoryview slices instead.") + "Buffer may not be acquired without the GIL. Consider using memoryview slices instead.") elif 'inline' in self.modifiers: warning(formal_arg.pos, "Buffer unpacking not optimized away.", 1) @@ -2416,13 +2416,13 @@ class CFuncDefNode(FuncDefNode): type.is_static_method = self.is_static_method self.entry = env.declare_cfunction( name, type, self.pos, - cname=cname, visibility=self.visibility, api=self.api, - defining=self.body is not None, modifiers=self.modifiers, - overridable=self.overridable) + cname=cname, visibility=self.visibility, api=self.api, + defining=self.body is not None, modifiers=self.modifiers, + overridable=self.overridable) self.entry.inline_func_in_pxd = self.inline_in_pxd self.return_type = type.return_type if self.return_type.is_array and self.visibility != 'extern': - error(self.pos, "Function cannot return an array") + error(self.pos, "Function cannot return an array") if self.return_type.is_cpp_class: self.return_type.check_nullary_constructor(self.pos, "used as a return value") @@ -2440,34 +2440,34 @@ class CFuncDefNode(FuncDefNode): # TODO(robertwb): Finish this up, perhaps via more function refactoring. error(self.pos, "static cpdef methods not yet supported") name = self.entry.name - py_func_body = self.call_self_node(is_module_scope=env.is_module_scope) + py_func_body = self.call_self_node(is_module_scope=env.is_module_scope) if self.is_static_method: from .ExprNodes import NameNode decorators = [DecoratorNode(self.pos, decorator=NameNode(self.pos, name='staticmethod'))] decorators[0].decorator.analyse_types(env) else: decorators = [] - self.py_func = DefNode(pos=self.pos, - name=self.entry.name, - args=self.args, - star_arg=None, - starstar_arg=None, - doc=self.doc, - body=py_func_body, - decorators=decorators, - is_wrapper=1) + self.py_func = DefNode(pos=self.pos, + name=self.entry.name, + args=self.args, + star_arg=None, + starstar_arg=None, + doc=self.doc, + body=py_func_body, + decorators=decorators, + is_wrapper=1) self.py_func.is_module_scope = env.is_module_scope self.py_func.analyse_declarations(env) - self.py_func.entry.is_overridable = True - self.py_func_stat = StatListNode(self.pos, stats=[self.py_func]) + self.py_func.entry.is_overridable = True + self.py_func_stat = StatListNode(self.pos, stats=[self.py_func]) self.py_func.type = PyrexTypes.py_object_type self.entry.as_variable = self.py_func.entry self.entry.used = self.entry.as_variable.used = True # Reset scope entry the above cfunction env.entries[name] = self.entry if (not self.entry.is_final_cmethod and - (not env.is_module_scope or Options.lookup_module_cpdef)): - self.override = OverrideCheckNode(self.pos, py_func=self.py_func) + (not env.is_module_scope or Options.lookup_module_cpdef)): + self.override = OverrideCheckNode(self.pos, py_func=self.py_func) self.body = StatListNode(self.pos, stats=[self.override, self.body]) def _validate_type_visibility(self, type, pos, env): @@ -2480,7 +2480,7 @@ class CFuncDefNode(FuncDefNode): if public_or_api and entry and env.is_module_scope: if not (entry.visibility in ('public', 'extern') or entry.api or entry.in_cinclude): - error(pos, "Function declared public or api may not have private types") + error(pos, "Function declared public or api may not have private types") def call_self_node(self, omit_optional_args=0, is_module_scope=0): from . import ExprNodes @@ -2535,22 +2535,22 @@ class CFuncDefNode(FuncDefNode): def analyse_expressions(self, env): self.local_scope.directives = env.directives - if self.py_func_stat is not None: - # this will also analyse the default values and the function name assignment - self.py_func_stat = self.py_func_stat.analyse_expressions(env) - elif self.py_func is not None: + if self.py_func_stat is not None: + # this will also analyse the default values and the function name assignment + self.py_func_stat = self.py_func_stat.analyse_expressions(env) + elif self.py_func is not None: # this will also analyse the default values self.py_func = self.py_func.analyse_expressions(env) else: self.analyse_default_values(env) - self.analyse_annotations(env) + self.analyse_annotations(env) self.acquire_gil = self.need_gil_acquisition(self.local_scope) return self def needs_assignment_synthesis(self, env, code=None): return False - def generate_function_header(self, code, with_pymethdef, with_opt_args=1, with_dispatch=1, cname=None): + def generate_function_header(self, code, with_pymethdef, with_opt_args=1, with_dispatch=1, cname=None): scope = self.local_scope arg_decls = [] type = self.type @@ -2591,8 +2591,8 @@ class CFuncDefNode(FuncDefNode): code.globalstate.parts['module_declarations'].putln(self.template_declaration) code.putln(self.template_declaration) if needs_proto: - code.globalstate.parts['module_declarations'].putln( - "%s%s%s; /* proto*/" % (storage_class, modifiers, header)) + code.globalstate.parts['module_declarations'].putln( + "%s%s%s; /* proto*/" % (storage_class, modifiers, header)) code.putln("%s%s%s {" % (storage_class, modifiers, header)) def generate_argument_declarations(self, env, code): @@ -2656,9 +2656,9 @@ class CFuncDefNode(FuncDefNode): self.generate_arg_none_check(arg, code) def generate_execution_code(self, code): - if code.globalstate.directives['linetrace']: - code.mark_pos(self.pos) - code.putln("") # generate line tracing code + if code.globalstate.directives['linetrace']: + code.mark_pos(self.pos) + code.putln("") # generate line tracing code super(CFuncDefNode, self).generate_execution_code(code) if self.py_func_stat: self.py_func_stat.generate_execution_code(code) @@ -2684,11 +2684,11 @@ class CFuncDefNode(FuncDefNode): entry = entry.prev_entry entry.func_cname = "%s%swrap_%s" % (self.entry.func_cname, Naming.pyrex_prefix, k) code.putln() - self.generate_function_header( - code, 0, - with_dispatch=entry.type.is_overridable, - with_opt_args=entry.type.optional_arg_count, - cname=entry.func_cname) + self.generate_function_header( + code, 0, + with_dispatch=entry.type.is_overridable, + with_opt_args=entry.type.optional_arg_count, + cname=entry.func_cname) if not self.return_type.is_void: code.put('return ') args = self.type.args @@ -2719,7 +2719,7 @@ class PyArgDeclNode(Node): def generate_function_definitions(self, env, code): self.entry.generate_function_definitions(env, code) - + class DecoratorNode(Node): # A decorator # @@ -2749,8 +2749,8 @@ class DefNode(FuncDefNode): # # decorator_indirection IndirectionNode Used to remove __Pyx_Method_ClassMethod for fused functions - child_attrs = ["args", "star_arg", "starstar_arg", "body", "decorators", "return_type_annotation"] - outer_attrs = ["decorators", "return_type_annotation"] + child_attrs = ["args", "star_arg", "starstar_arg", "body", "decorators", "return_type_annotation"] + outer_attrs = ["decorators", "return_type_annotation"] is_staticmethod = False is_classmethod = False @@ -2791,8 +2791,8 @@ class DefNode(FuncDefNode): self.num_required_kw_args = rk self.num_required_args = r - def as_cfunction(self, cfunc=None, scope=None, overridable=True, returns=None, except_val=None, modifiers=None, - nogil=False, with_gil=False): + def as_cfunction(self, cfunc=None, scope=None, overridable=True, returns=None, except_val=None, modifiers=None, + nogil=False, with_gil=False): if self.star_arg: error(self.star_arg.pos, "cdef function cannot have star argument") if self.starstar_arg: @@ -2803,19 +2803,19 @@ class DefNode(FuncDefNode): cfunc_args = [] for formal_arg in self.args: name_declarator, type = formal_arg.analyse(scope, nonempty=1) - cfunc_args.append(PyrexTypes.CFuncTypeArg(name=name_declarator.name, - cname=None, + cfunc_args.append(PyrexTypes.CFuncTypeArg(name=name_declarator.name, + cname=None, annotation=formal_arg.annotation, - type=py_object_type, - pos=formal_arg.pos)) - cfunc_type = PyrexTypes.CFuncType(return_type=py_object_type, - args=cfunc_args, - has_varargs=False, - exception_value=None, + type=py_object_type, + pos=formal_arg.pos)) + cfunc_type = PyrexTypes.CFuncType(return_type=py_object_type, + args=cfunc_args, + has_varargs=False, + exception_value=None, exception_check=exception_check, - nogil=nogil, - with_gil=with_gil, - is_overridable=overridable) + nogil=nogil, + with_gil=with_gil, + is_overridable=overridable) cfunc = CVarDefNode(self.pos, type=cfunc_type) else: if scope is None: @@ -2826,7 +2826,7 @@ class DefNode(FuncDefNode): error(cfunc.pos, "previous declaration here") for i, (formal_arg, type_arg) in enumerate(zip(self.args, cfunc_type.args)): name_declarator, type = formal_arg.analyse(scope, nonempty=1, - is_self_arg=(i == 0 and scope.is_c_class_scope)) + is_self_arg=(i == 0 and scope.is_c_class_scope)) if type is None or type is PyrexTypes.py_object_type: formal_arg.type = type_arg.type formal_arg.name_declarator = name_declarator @@ -2834,29 +2834,29 @@ class DefNode(FuncDefNode): if exception_value is None and cfunc_type.exception_value is not None: from .ExprNodes import ConstNode exception_value = ConstNode( - self.pos, value=cfunc_type.exception_value, type=cfunc_type.return_type) + self.pos, value=cfunc_type.exception_value, type=cfunc_type.return_type) declarator = CFuncDeclaratorNode(self.pos, - base=CNameDeclaratorNode(self.pos, name=self.name, cname=None), - args=self.args, - has_varargs=False, - exception_check=cfunc_type.exception_check, - exception_value=exception_value, - with_gil=cfunc_type.with_gil, - nogil=cfunc_type.nogil) + base=CNameDeclaratorNode(self.pos, name=self.name, cname=None), + args=self.args, + has_varargs=False, + exception_check=cfunc_type.exception_check, + exception_value=exception_value, + with_gil=cfunc_type.with_gil, + nogil=cfunc_type.nogil) return CFuncDefNode(self.pos, - modifiers=modifiers or [], - base_type=CAnalysedBaseTypeNode(self.pos, type=cfunc_type.return_type), - declarator=declarator, - body=self.body, - doc=self.doc, - overridable=cfunc_type.is_overridable, - type=cfunc_type, - with_gil=cfunc_type.with_gil, - nogil=cfunc_type.nogil, - visibility='private', - api=False, - directive_locals=getattr(cfunc, 'directive_locals', {}), - directive_returns=returns) + modifiers=modifiers or [], + base_type=CAnalysedBaseTypeNode(self.pos, type=cfunc_type.return_type), + declarator=declarator, + body=self.body, + doc=self.doc, + overridable=cfunc_type.is_overridable, + type=cfunc_type, + with_gil=cfunc_type.with_gil, + nogil=cfunc_type.nogil, + visibility='private', + api=False, + directive_locals=getattr(cfunc, 'directive_locals', {}), + directive_returns=returns) def is_cdef_func_compatible(self): """Determines if the function's signature is compatible with a @@ -2895,13 +2895,13 @@ class DefNode(FuncDefNode): self.analyse_signature(env) self.return_type = self.entry.signature.return_type() - # if a signature annotation provides a more specific return object type, use it - if self.return_type is py_object_type and self.return_type_annotation: - if env.directives['annotation_typing'] and not self.entry.is_special: + # if a signature annotation provides a more specific return object type, use it + if self.return_type is py_object_type and self.return_type_annotation: + if env.directives['annotation_typing'] and not self.entry.is_special: _, return_type = analyse_type_annotation(self.return_type_annotation, env) - if return_type and return_type.is_pyobject: - self.return_type = return_type - + if return_type and return_type.is_pyobject: + self.return_type = return_type + self.create_local_scope(env) self.py_wrapper = DefNodeWrapper( @@ -2915,7 +2915,7 @@ class DefNode(FuncDefNode): self.py_wrapper.analyse_declarations(env) def analyse_argument_types(self, env): - self.directive_locals = env.directives.get('locals', {}) + self.directive_locals = env.directives.get('locals', {}) allow_none_for_extension_args = env.directives['allow_none_for_extension_args'] f2s = env.fused_to_specific @@ -2943,7 +2943,7 @@ class DefNode(FuncDefNode): self.align_argument_type(env, arg) if name_declarator and name_declarator.cname: - error(self.pos, "Python function argument cannot have C name specification") + error(self.pos, "Python function argument cannot have C name specification") arg.type = arg.type.as_argument_type() arg.hdr_type = None arg.needs_conversion = 0 @@ -2955,7 +2955,7 @@ class DefNode(FuncDefNode): elif arg.not_none: arg.accept_none = False elif (arg.type.is_extension_type or arg.type.is_builtin_type - or arg.type.is_buffer or arg.type.is_memoryviewslice): + or arg.type.is_buffer or arg.type.is_memoryviewslice): if arg.default and arg.default.constant_result is None: # special case: def func(MyType obj = None) arg.accept_none = True @@ -3000,8 +3000,8 @@ class DefNode(FuncDefNode): sig = self.entry.signature nfixed = sig.num_fixed_args() - if (sig is TypeSlots.pymethod_signature and nfixed == 1 - and len(self.args) == 0 and self.star_arg): + if (sig is TypeSlots.pymethod_signature and nfixed == 1 + and len(self.args) == 0 and self.star_arg): # this is the only case where a diverging number of # arguments is not an error - when we have no explicit # 'self' parameter as in method(*args) @@ -3019,7 +3019,7 @@ class DefNode(FuncDefNode): sig.has_generic_args = True if ((self.is_classmethod or self.is_staticmethod) and - self.has_fused_arguments and env.is_c_class_scope): + self.has_fused_arguments and env.is_c_class_scope): del self.decorator_indirection.stats[:] for i in range(min(nfixed, len(self.args))): @@ -3052,7 +3052,7 @@ class DefNode(FuncDefNode): if not sig.has_generic_args: self.bad_signature() for arg in self.args: - if arg.is_generic and (arg.type.is_extension_type or arg.type.is_builtin_type): + if arg.is_generic and (arg.type.is_extension_type or arg.type.is_builtin_type): arg.needs_type_test = 1 def bad_signature(self): @@ -3065,8 +3065,8 @@ class DefNode(FuncDefNode): desc = "Special method" else: desc = "Method" - error(self.pos, "%s %s has wrong number of arguments (%d declared, %s expected)" % ( - desc, self.name, len(self.args), expected_str)) + error(self.pos, "%s %s has wrong number of arguments (%d declared, %s expected)" % ( + desc, self.name, len(self.args), expected_str)) def declare_pyfunction(self, env): #print "DefNode.declare_pyfunction:", self.name, "in", env ### @@ -3075,7 +3075,7 @@ class DefNode(FuncDefNode): if entry: if entry.is_final_cmethod and not env.parent_type.is_final_type: error(self.pos, "Only final types can have final Python (def/cpdef) methods") - if entry.type.is_cfunction and not entry.is_builtin_cmethod and not self.is_wrapper: + if entry.type.is_cfunction and not entry.is_builtin_cmethod and not self.is_wrapper: warning(self.pos, "Overriding cdef method with def method.", 5) entry = env.declare_pyfunction(name, self.pos, allow_redefine=not self.is_wrapper) self.entry = entry @@ -3085,8 +3085,8 @@ class DefNode(FuncDefNode): entry.doc = embed_position(self.pos, self.doc) entry.doc_cname = Naming.funcdoc_prefix + prefix + name if entry.is_special: - if entry.name in TypeSlots.invisible or not entry.doc or ( - entry.name in '__getattr__' and env.directives['fast_getattr']): + if entry.name in TypeSlots.invisible or not entry.doc or ( + entry.name in '__getattr__' and env.directives['fast_getattr']): entry.wrapperbase_cname = None else: entry.wrapperbase_cname = Naming.wrapperbase_prefix + prefix + name @@ -3131,8 +3131,8 @@ class DefNode(FuncDefNode): def analyse_expressions(self, env): self.local_scope.directives = env.directives self.analyse_default_values(env) - self.analyse_annotations(env) - if self.return_type_annotation: + self.analyse_annotations(env) + if self.return_type_annotation: self.return_type_annotation = self.analyse_annotation(env, self.return_type_annotation) if not self.needs_assignment_synthesis(env) and self.decorators: @@ -3145,17 +3145,17 @@ class DefNode(FuncDefNode): def needs_assignment_synthesis(self, env, code=None): if self.is_staticmethod: return True - if self.specialized_cpdefs or self.entry.is_fused_specialized: + if self.specialized_cpdefs or self.entry.is_fused_specialized: return False if self.no_assignment_synthesis: return False - if self.entry.is_special: - return False + if self.entry.is_special: + return False if self.entry.is_anonymous: return True - if env.is_module_scope or env.is_c_class_scope: + if env.is_module_scope or env.is_c_class_scope: if code is None: - return self.local_scope.directives['binding'] + return self.local_scope.directives['binding'] else: return code.globalstate.directives['binding'] return env.is_py_class_scope or env.is_closure_scope @@ -3168,8 +3168,8 @@ class DefNode(FuncDefNode): def generate_function_definitions(self, env, code): if self.defaults_getter: - # defaults getter must never live in class scopes, it's always a module function - self.defaults_getter.generate_function_definitions(env.global_scope(), code) + # defaults getter must never live in class scopes, it's always a module function + self.defaults_getter.generate_function_definitions(env.global_scope(), code) # Before closure cnames are mangled if self.py_wrapper_required: @@ -3291,15 +3291,15 @@ class DefNodeWrapper(FuncDefNode): if not arg.hdr_type.create_to_py_utility_code(env): pass # will fail later - if self.starstar_arg and not self.starstar_arg.entry.cf_used: - # we will set the kwargs argument to NULL instead of a new dict - # and must therefore correct the control flow state - entry = self.starstar_arg.entry - entry.xdecref_cleanup = 1 - for ass in entry.cf_assignments: - if not ass.is_arg and ass.lhs.is_name: - ass.lhs.cf_maybe_null = True - + if self.starstar_arg and not self.starstar_arg.entry.cf_used: + # we will set the kwargs argument to NULL instead of a new dict + # and must therefore correct the control flow state + entry = self.starstar_arg.entry + entry.xdecref_cleanup = 1 + for ass in entry.cf_assignments: + if not ass.is_arg and ass.lhs.is_name: + ass.lhs.cf_maybe_null = True + def signature_has_nongeneric_args(self): argcount = len(self.args) if argcount == 0 or ( @@ -3342,7 +3342,7 @@ class DefNodeWrapper(FuncDefNode): if preprocessor_guard: code.putln(preprocessor_guard) - code.enter_cfunc_scope(lenv) + code.enter_cfunc_scope(lenv) code.return_from_error_cleanup_label = code.new_label() with_pymethdef = (self.target.needs_assignment_synthesis(env, code) or @@ -3421,14 +3421,14 @@ class DefNodeWrapper(FuncDefNode): arg_code_list.append("CYTHON_UNUSED PyObject *unused") if sig.has_generic_args: arg_code_list.append( - "PyObject *%s, PyObject *%s" % ( - Naming.args_cname, Naming.kwds_cname)) + "PyObject *%s, PyObject *%s" % ( + Naming.args_cname, Naming.kwds_cname)) arg_code = ", ".join(arg_code_list) # Prevent warning: unused function '__pyx_pw_5numpy_7ndarray_1__getbuffer__' mf = "" if (entry.name in ("__getbuffer__", "__releasebuffer__") - and entry.scope.is_c_class_scope): + and entry.scope.is_c_class_scope): mf = "CYTHON_UNUSED " with_pymethdef = False @@ -3442,7 +3442,7 @@ class DefNodeWrapper(FuncDefNode): # want the prototype for the "fused cpdef", in case we're # checking to see if our method was overridden in Python self.target.fused_py_func.generate_function_header( - code, with_pymethdef, proto_only=True) + code, with_pymethdef, proto_only=True) return if (Options.docstrings and entry.doc and @@ -3453,12 +3453,12 @@ class DefNodeWrapper(FuncDefNode): docstr = entry.doc if docstr.is_unicode: - docstr = docstr.as_utf8_string() + docstr = docstr.as_utf8_string() - if not (entry.is_special and entry.name in ('__getbuffer__', '__releasebuffer__')): - code.putln('static char %s[] = %s;' % ( + if not (entry.is_special and entry.name in ('__getbuffer__', '__releasebuffer__')): + code.putln('static char %s[] = %s;' % ( entry.doc_cname, - docstr.as_c_string_literal())) + docstr.as_c_string_literal())) if entry.is_special: code.putln('#if CYTHON_COMPILING_IN_CPYTHON') @@ -3468,7 +3468,7 @@ class DefNodeWrapper(FuncDefNode): if with_pymethdef or self.target.fused_py_func: code.put( - "static PyMethodDef %s = " % entry.pymethdef_cname) + "static PyMethodDef %s = " % entry.pymethdef_cname) code.put_pymethoddef(self.target.entry, ";", allow_skip=False) code.putln("%s {" % header) @@ -3497,7 +3497,7 @@ class DefNodeWrapper(FuncDefNode): for arg in self.args: if not arg.type.is_pyobject: if not arg.type.create_from_py_utility_code(env): - pass # will fail later + pass # will fail later if not self.signature_has_generic_args(): if has_star_or_kw_args: @@ -3544,11 +3544,11 @@ class DefNodeWrapper(FuncDefNode): code.putln("if (unlikely(PyTuple_GET_SIZE(%s) > 0)) {" % Naming.args_cname) code.put('__Pyx_RaiseArgtupleInvalid("%s", 1, 0, 0, PyTuple_GET_SIZE(%s)); return %s;' % ( - self.name, Naming.args_cname, self.error_value())) + self.name, Naming.args_cname, self.error_value())) code.putln("}") if self.starstar_arg: - if self.star_arg or not self.starstar_arg.entry.cf_used: + if self.star_arg or not self.starstar_arg.entry.cf_used: kwarg_check = "unlikely(%s)" % Naming.kwds_cname else: kwarg_check = "%s" % Naming.kwds_cname @@ -3562,38 +3562,38 @@ class DefNodeWrapper(FuncDefNode): kwarg_check, Naming.kwds_cname, self.name, bool(self.starstar_arg), self.error_value())) - if self.starstar_arg and self.starstar_arg.entry.cf_used: - if all(ref.node.allow_null for ref in self.starstar_arg.entry.cf_references): - code.putln("if (%s) {" % kwarg_check) - code.putln("%s = PyDict_Copy(%s); if (unlikely(!%s)) return %s;" % ( - self.starstar_arg.entry.cname, - Naming.kwds_cname, - self.starstar_arg.entry.cname, - self.error_value())) - code.put_gotref(self.starstar_arg.entry.cname) - code.putln("} else {") - code.putln("%s = NULL;" % (self.starstar_arg.entry.cname,)) - code.putln("}") - self.starstar_arg.entry.xdecref_cleanup = 1 - else: - code.put("%s = (%s) ? PyDict_Copy(%s) : PyDict_New(); " % ( - self.starstar_arg.entry.cname, - Naming.kwds_cname, - Naming.kwds_cname)) - code.putln("if (unlikely(!%s)) return %s;" % ( - self.starstar_arg.entry.cname, self.error_value())) - self.starstar_arg.entry.xdecref_cleanup = 0 - code.put_gotref(self.starstar_arg.entry.cname) + if self.starstar_arg and self.starstar_arg.entry.cf_used: + if all(ref.node.allow_null for ref in self.starstar_arg.entry.cf_references): + code.putln("if (%s) {" % kwarg_check) + code.putln("%s = PyDict_Copy(%s); if (unlikely(!%s)) return %s;" % ( + self.starstar_arg.entry.cname, + Naming.kwds_cname, + self.starstar_arg.entry.cname, + self.error_value())) + code.put_gotref(self.starstar_arg.entry.cname) + code.putln("} else {") + code.putln("%s = NULL;" % (self.starstar_arg.entry.cname,)) + code.putln("}") + self.starstar_arg.entry.xdecref_cleanup = 1 + else: + code.put("%s = (%s) ? PyDict_Copy(%s) : PyDict_New(); " % ( + self.starstar_arg.entry.cname, + Naming.kwds_cname, + Naming.kwds_cname)) + code.putln("if (unlikely(!%s)) return %s;" % ( + self.starstar_arg.entry.cname, self.error_value())) + self.starstar_arg.entry.xdecref_cleanup = 0 + code.put_gotref(self.starstar_arg.entry.cname) if self.self_in_stararg and not self.target.is_staticmethod: # need to create a new tuple with 'self' inserted as first item code.put("%s = PyTuple_New(PyTuple_GET_SIZE(%s)+1); if (unlikely(!%s)) " % ( - self.star_arg.entry.cname, - Naming.args_cname, - self.star_arg.entry.cname)) - if self.starstar_arg and self.starstar_arg.entry.cf_used: + self.star_arg.entry.cname, + Naming.args_cname, + self.star_arg.entry.cname)) + if self.starstar_arg and self.starstar_arg.entry.cf_used: code.putln("{") - code.put_xdecref_clear(self.starstar_arg.entry.cname, py_object_type) + code.put_xdecref_clear(self.starstar_arg.entry.cname, py_object_type) code.putln("return %s;" % self.error_value()) code.putln("}") else: @@ -3618,8 +3618,8 @@ class DefNodeWrapper(FuncDefNode): elif self.star_arg: code.put_incref(Naming.args_cname, py_object_type) code.putln("%s = %s;" % ( - self.star_arg.entry.cname, - Naming.args_cname)) + self.star_arg.entry.cname, + Naming.args_cname)) self.star_arg.entry.xdecref_cleanup = 0 def generate_tuple_and_keyword_parsing_code(self, args, success_label, code): @@ -3660,8 +3660,8 @@ class DefNodeWrapper(FuncDefNode): all_args = tuple(positional_args) + tuple(kw_only_args) code.putln("static PyObject **%s[] = {%s,0};" % ( Naming.pykwdlist_cname, - ','.join(['&%s' % code.intern_identifier(arg.name) - for arg in all_args]))) + ','.join(['&%s' % code.intern_identifier(arg.name) + for arg in all_args]))) # Before being converted and assigned to the target variables, # borrowed references to all unpacked argument values are @@ -3691,14 +3691,14 @@ class DefNodeWrapper(FuncDefNode): else: compare = '<' code.putln('} else if (PyTuple_GET_SIZE(%s) %s %d) {' % ( - Naming.args_cname, compare, min_positional_args)) + Naming.args_cname, compare, min_positional_args)) code.put_goto(argtuple_error_label) if self.num_required_kw_args: # pure error case: keywords required but not passed if max_positional_args > min_positional_args and not self.star_arg: code.putln('} else if (PyTuple_GET_SIZE(%s) > %d) {' % ( - Naming.args_cname, max_positional_args)) + Naming.args_cname, max_positional_args)) code.put_goto(argtuple_error_label) code.putln('} else {') for i, arg in enumerate(kw_only_args): @@ -3708,8 +3708,8 @@ class DefNodeWrapper(FuncDefNode): code.globalstate.use_utility_code( UtilityCode.load_cached("RaiseKeywordRequired", "FunctionArguments.c")) code.put('__Pyx_RaiseKeywordRequired("%s", %s); ' % ( - self.name, - pystring_cname)) + self.name, + pystring_cname)) code.putln(code.error_goto(self.pos)) break @@ -3764,9 +3764,9 @@ class DefNodeWrapper(FuncDefNode): code.globalstate.use_utility_code( UtilityCode.load_cached("RaiseArgTupleInvalid", "FunctionArguments.c")) code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d, PyTuple_GET_SIZE(%s)); ' % ( - self.name, has_fixed_positional_count, - min_positional_args, max_positional_args, - Naming.args_cname)) + self.name, has_fixed_positional_count, + min_positional_args, max_positional_args, + Naming.args_cname)) code.putln(code.error_goto(self.pos)) def generate_arg_assignment(self, arg, item, code): @@ -3785,9 +3785,9 @@ class DefNodeWrapper(FuncDefNode): item, arg.entry.cname, arg.pos, code)) if arg.default: code.putln('} else {') - code.putln("%s = %s;" % ( - arg.entry.cname, - arg.calculate_default_value_code(code))) + code.putln("%s = %s;" % ( + arg.entry.cname, + arg.calculate_default_value_code(code))) if arg.type.is_memoryviewslice: code.put_incref_memoryviewslice(arg.entry.cname, have_gil=True) @@ -3799,18 +3799,18 @@ class DefNodeWrapper(FuncDefNode): if self.starstar_arg: self.starstar_arg.entry.xdecref_cleanup = 0 code.putln('%s = PyDict_New(); if (unlikely(!%s)) return %s;' % ( - self.starstar_arg.entry.cname, - self.starstar_arg.entry.cname, - self.error_value())) + self.starstar_arg.entry.cname, + self.starstar_arg.entry.cname, + self.error_value())) code.put_gotref(self.starstar_arg.entry.cname) if self.star_arg: self.star_arg.entry.xdecref_cleanup = 0 code.putln('if (PyTuple_GET_SIZE(%s) > %d) {' % ( - Naming.args_cname, - max_positional_args)) + Naming.args_cname, + max_positional_args)) code.putln('%s = PyTuple_GetSlice(%s, %d, PyTuple_GET_SIZE(%s));' % ( - self.star_arg.entry.cname, Naming.args_cname, - max_positional_args, Naming.args_cname)) + self.star_arg.entry.cname, Naming.args_cname, + max_positional_args, Naming.args_cname)) code.putln("if (unlikely(!%s)) {" % self.star_arg.entry.cname) if self.starstar_arg: code.put_decref_clear(self.starstar_arg.entry.cname, py_object_type) @@ -3854,7 +3854,7 @@ class DefNodeWrapper(FuncDefNode): for i in range(max_positional_args-1, -1, -1): code.put('case %2d: ' % (i+1)) code.putln("values[%d] = PyTuple_GET_ITEM(%s, %d);" % ( - i, Naming.args_cname, i)) + i, Naming.args_cname, i)) code.putln('CYTHON_FALLTHROUGH;') code.putln('case 0: break;') if not self.star_arg: @@ -3916,16 +3916,16 @@ class DefNodeWrapper(FuncDefNode): code.globalstate.use_utility_code( UtilityCode.load_cached("RaiseArgTupleInvalid", "FunctionArguments.c")) code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d, %d); ' % ( - self.name, has_fixed_positional_count, - min_positional_args, max_positional_args, i)) + self.name, has_fixed_positional_count, + min_positional_args, max_positional_args, i)) code.putln(code.error_goto(self.pos)) code.putln('}') elif arg.kw_only: code.putln('else {') code.globalstate.use_utility_code( UtilityCode.load_cached("RaiseKeywordRequired", "FunctionArguments.c")) - code.put('__Pyx_RaiseKeywordRequired("%s", %s); ' % ( - self.name, pystring_cname)) + code.put('__Pyx_RaiseKeywordRequired("%s", %s); ' % ( + self.name, pystring_cname)) code.putln(code.error_goto(self.pos)) code.putln('}') if max_positional_args > 0: @@ -3948,19 +3948,19 @@ class DefNodeWrapper(FuncDefNode): pos_arg_count = "0" elif self.star_arg: code.putln("const Py_ssize_t used_pos_args = (pos_args < %d) ? pos_args : %d;" % ( - max_positional_args, max_positional_args)) + max_positional_args, max_positional_args)) pos_arg_count = "used_pos_args" else: pos_arg_count = "pos_args" code.globalstate.use_utility_code( UtilityCode.load_cached("ParseKeywords", "FunctionArguments.c")) - code.putln('if (unlikely(__Pyx_ParseOptionalKeywords(%s, %s, %s, values, %s, "%s") < 0)) %s' % ( - Naming.kwds_cname, - Naming.pykwdlist_cname, - self.starstar_arg and self.starstar_arg.entry.cname or '0', - pos_arg_count, - self.name, - code.error_goto(self.pos))) + code.putln('if (unlikely(__Pyx_ParseOptionalKeywords(%s, %s, %s, values, %s, "%s") < 0)) %s' % ( + Naming.kwds_cname, + Naming.pykwdlist_cname, + self.starstar_arg and self.starstar_arg.entry.cname or '0', + pos_arg_count, + self.name, + code.error_goto(self.pos))) code.putln('}') def generate_optional_kwonly_args_unpacking_code(self, all_args, code): @@ -4017,9 +4017,9 @@ class DefNodeWrapper(FuncDefNode): self.generate_arg_conversion_to_pyobject(arg, code) else: if new_type.assignable_from(old_type): - code.putln("%s = %s;" % (arg.entry.cname, arg.hdr_cname)) + code.putln("%s = %s;" % (arg.entry.cname, arg.hdr_cname)) else: - error(arg.pos, "Cannot convert 1 argument from '%s' to '%s'" % (old_type, new_type)) + error(arg.pos, "Cannot convert 1 argument from '%s' to '%s'" % (old_type, new_type)) def generate_arg_conversion_from_pyobject(self, arg, code): new_type = arg.type @@ -4032,7 +4032,7 @@ class DefNodeWrapper(FuncDefNode): code, )) else: - error(arg.pos, "Cannot convert Python object argument to type '%s'" % new_type) + error(arg.pos, "Cannot convert Python object argument to type '%s'" % new_type) def generate_arg_conversion_to_pyobject(self, arg, code): old_type = arg.hdr_type @@ -4045,7 +4045,7 @@ class DefNodeWrapper(FuncDefNode): code.error_goto_if_null(arg.entry.cname, arg.pos))) code.put_var_gotref(arg.entry) else: - error(arg.pos, "Cannot convert argument of type '%s' to Python object" % old_type) + error(arg.pos, "Cannot convert argument of type '%s' to Python object" % old_type) def generate_argument_type_tests(self, code): # Generate type tests for args whose signature @@ -4070,7 +4070,7 @@ class GeneratorDefNode(DefNode): # is_generator = True - is_coroutine = False + is_coroutine = False is_iterable_coroutine = False is_asyncgen = False gen_type_name = 'Generator' @@ -4092,10 +4092,10 @@ class GeneratorDefNode(DefNode): body_cname = self.gbody.entry.func_cname name = code.intern_identifier(self.name) qualname = code.intern_identifier(self.qualname) - module_name = code.intern_identifier(self.module_name) + module_name = code.intern_identifier(self.module_name) code.putln('{') - code.putln('__pyx_CoroutineObject *gen = __Pyx_%s_New(' + code.putln('__pyx_CoroutineObject *gen = __Pyx_%s_New(' '(__pyx_coroutine_body_t) %s, %s, (PyObject *) %s, %s, %s, %s); %s' % ( self.gen_type_name, body_cname, self.code_object.calculate_result_code(code) if self.code_object else 'NULL', @@ -4119,11 +4119,11 @@ class GeneratorDefNode(DefNode): self.gbody.generate_function_definitions(env, code) -class AsyncDefNode(GeneratorDefNode): +class AsyncDefNode(GeneratorDefNode): gen_type_name = 'Coroutine' - is_coroutine = True - - + is_coroutine = True + + class IterableAsyncDefNode(AsyncDefNode): gen_type_name = 'IterableCoroutine' is_iterable_coroutine = True @@ -4139,9 +4139,9 @@ class GeneratorBodyDefNode(DefNode): # is_generator_body = True - is_inlined = False + is_inlined = False is_async_gen_body = False - inlined_comprehension_type = None # container type for inlined comprehensions + inlined_comprehension_type = None # container type for inlined comprehensions def __init__(self, pos=None, name=None, body=None, is_async_gen_body=False): super(GeneratorBodyDefNode, self).__init__( @@ -4184,7 +4184,7 @@ class GeneratorBodyDefNode(DefNode): self.body.generate_function_definitions(lenv, code) # Generate C code for header and body of function - code.enter_cfunc_scope(lenv) + code.enter_cfunc_scope(lenv) code.return_from_error_cleanup_label = code.new_label() # ----- Top-level constants used by this function @@ -4217,23 +4217,23 @@ class GeneratorBodyDefNode(DefNode): code.putln('%s' % (code.error_goto_if_null(Naming.sent_value_cname, self.pos))) - # ----- prepare target container for inlined comprehension - if self.is_inlined and self.inlined_comprehension_type is not None: - target_type = self.inlined_comprehension_type - if target_type is Builtin.list_type: - comp_init = 'PyList_New(0)' - elif target_type is Builtin.set_type: - comp_init = 'PySet_New(NULL)' - elif target_type is Builtin.dict_type: - comp_init = 'PyDict_New()' - else: - raise InternalError( - "invalid type of inlined comprehension: %s" % target_type) - code.putln("%s = %s; %s" % ( - Naming.retval_cname, comp_init, - code.error_goto_if_null(Naming.retval_cname, self.pos))) - code.put_gotref(Naming.retval_cname) - + # ----- prepare target container for inlined comprehension + if self.is_inlined and self.inlined_comprehension_type is not None: + target_type = self.inlined_comprehension_type + if target_type is Builtin.list_type: + comp_init = 'PyList_New(0)' + elif target_type is Builtin.set_type: + comp_init = 'PySet_New(NULL)' + elif target_type is Builtin.dict_type: + comp_init = 'PyDict_New()' + else: + raise InternalError( + "invalid type of inlined comprehension: %s" % target_type) + code.putln("%s = %s; %s" % ( + Naming.retval_cname, comp_init, + code.error_goto_if_null(Naming.retval_cname, self.pos))) + code.put_gotref(Naming.retval_cname) + # ----- Function body self.generate_function_body(env, code) # ----- Closure initialization @@ -4242,8 +4242,8 @@ class GeneratorBodyDefNode(DefNode): lenv.scope_class.type.declaration_code(Naming.cur_scope_cname), lenv.scope_class.type.cast_code('%s->closure' % Naming.generator_cname))) - # FIXME: this silences a potential "unused" warning => try to avoid unused closures in more cases - code.putln("CYTHON_MAYBE_UNUSED_VAR(%s);" % Naming.cur_scope_cname) + # FIXME: this silences a potential "unused" warning => try to avoid unused closures in more cases + code.putln("CYTHON_MAYBE_UNUSED_VAR(%s);" % Naming.cur_scope_cname) if profile or linetrace: code.funcstate.can_trace = False @@ -4254,7 +4254,7 @@ class GeneratorBodyDefNode(DefNode): # on normal generator termination, we do not take the exception propagation # path: no traceback info is required and not creating it is much faster - if not self.is_inlined and not self.body.is_terminator: + if not self.is_inlined and not self.body.is_terminator: if self.is_async_gen_body: code.globalstate.use_utility_code( UtilityCode.load_cached("StopAsyncIteration", "Coroutine.c")) @@ -4265,11 +4265,11 @@ class GeneratorBodyDefNode(DefNode): if not self.body.is_terminator: code.put_goto(code.return_label) code.put_label(code.error_label) - if self.is_inlined and self.inlined_comprehension_type is not None: - code.put_xdecref_clear(Naming.retval_cname, py_object_type) - if Future.generator_stop in env.global_scope().context.future_directives: - # PEP 479: turn accidental StopIteration exceptions into a RuntimeError - code.globalstate.use_utility_code(UtilityCode.load_cached("pep479", "Coroutine.c")) + if self.is_inlined and self.inlined_comprehension_type is not None: + code.put_xdecref_clear(Naming.retval_cname, py_object_type) + if Future.generator_stop in env.global_scope().context.future_directives: + # PEP 479: turn accidental StopIteration exceptions into a RuntimeError + code.globalstate.use_utility_code(UtilityCode.load_cached("pep479", "Coroutine.c")) code.putln("__Pyx_Generator_Replace_StopIteration(%d);" % bool(self.is_async_gen_body)) for cname, type in code.funcstate.all_managed_temps(): code.put_xdecref(cname, type) @@ -4277,22 +4277,22 @@ class GeneratorBodyDefNode(DefNode): # ----- Non-error return cleanup code.put_label(code.return_label) - if self.is_inlined: - code.put_xgiveref(Naming.retval_cname) - else: - code.put_xdecref_clear(Naming.retval_cname, py_object_type) - # For Py3.7, clearing is already done below. - code.putln("#if !CYTHON_USE_EXC_INFO_STACK") + if self.is_inlined: + code.put_xgiveref(Naming.retval_cname) + else: + code.put_xdecref_clear(Naming.retval_cname, py_object_type) + # For Py3.7, clearing is already done below. + code.putln("#if !CYTHON_USE_EXC_INFO_STACK") code.putln("__Pyx_Coroutine_ResetAndClearException(%s);" % Naming.generator_cname) - code.putln("#endif") + code.putln("#endif") code.putln('%s->resume_label = -1;' % Naming.generator_cname) # clean up as early as possible to help breaking any reference cycles - code.putln('__Pyx_Coroutine_clear((PyObject*)%s);' % Naming.generator_cname) + code.putln('__Pyx_Coroutine_clear((PyObject*)%s);' % Naming.generator_cname) if profile or linetrace: code.put_trace_return(Naming.retval_cname, nogil=not code.funcstate.gil_owned) code.put_finish_refcount_context() - code.putln("return %s;" % Naming.retval_cname) + code.putln("return %s;" % Naming.retval_cname) code.putln("}") # ----- Go back and insert temp variable declarations @@ -4343,14 +4343,14 @@ class OverrideCheckNode(StatNode): self.func_node = ExprNodes.RawCNameExprNode(self.pos, py_object_type) call_node = ExprNodes.SimpleCallNode( self.pos, function=self.func_node, - args=[ExprNodes.NameNode(self.pos, name=arg.name) - for arg in self.args[first_arg:]]) - if env.return_type.is_void or env.return_type.is_returncode: - self.body = StatListNode(self.pos, stats=[ - ExprStatNode(self.pos, expr=call_node), - ReturnStatNode(self.pos, value=None)]) - else: - self.body = ReturnStatNode(self.pos, value=call_node) + args=[ExprNodes.NameNode(self.pos, name=arg.name) + for arg in self.args[first_arg:]]) + if env.return_type.is_void or env.return_type.is_returncode: + self.body = StatListNode(self.pos, stats=[ + ExprStatNode(self.pos, expr=call_node), + ReturnStatNode(self.pos, value=None)]) + else: + self.body = ReturnStatNode(self.pos, value=call_node) self.body = self.body.analyse_expressions(env) return self @@ -4367,25 +4367,25 @@ class OverrideCheckNode(StatNode): if self.py_func.is_module_scope: code.putln("else {") else: - code.putln("else if (unlikely((Py_TYPE(%s)->tp_dictoffset != 0)" - " || (Py_TYPE(%s)->tp_flags & (Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_HEAPTYPE)))) {" % ( - self_arg, self_arg)) - - code.putln("#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS") - code.globalstate.use_utility_code( - UtilityCode.load_cached("PyDictVersioning", "ObjectHandling.c")) - # TODO: remove the object dict version check by 'inlining' the getattr implementation for methods. - # This would allow checking the dict versions around _PyType_Lookup() if it returns a descriptor, - # and would (tada!) make this check a pure type based thing instead of supporting only a single - # instance at a time. - code.putln("static PY_UINT64_T %s = __PYX_DICT_VERSION_INIT, %s = __PYX_DICT_VERSION_INIT;" % ( - Naming.tp_dict_version_temp, Naming.obj_dict_version_temp)) - code.putln("if (unlikely(!__Pyx_object_dict_version_matches(%s, %s, %s))) {" % ( - self_arg, Naming.tp_dict_version_temp, Naming.obj_dict_version_temp)) - code.putln("PY_UINT64_T %s = __Pyx_get_tp_dict_version(%s);" % ( - Naming.type_dict_guard_temp, self_arg)) - code.putln("#endif") - + code.putln("else if (unlikely((Py_TYPE(%s)->tp_dictoffset != 0)" + " || (Py_TYPE(%s)->tp_flags & (Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_HEAPTYPE)))) {" % ( + self_arg, self_arg)) + + code.putln("#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS") + code.globalstate.use_utility_code( + UtilityCode.load_cached("PyDictVersioning", "ObjectHandling.c")) + # TODO: remove the object dict version check by 'inlining' the getattr implementation for methods. + # This would allow checking the dict versions around _PyType_Lookup() if it returns a descriptor, + # and would (tada!) make this check a pure type based thing instead of supporting only a single + # instance at a time. + code.putln("static PY_UINT64_T %s = __PYX_DICT_VERSION_INIT, %s = __PYX_DICT_VERSION_INIT;" % ( + Naming.tp_dict_version_temp, Naming.obj_dict_version_temp)) + code.putln("if (unlikely(!__Pyx_object_dict_version_matches(%s, %s, %s))) {" % ( + self_arg, Naming.tp_dict_version_temp, Naming.obj_dict_version_temp)) + code.putln("PY_UINT64_T %s = __Pyx_get_tp_dict_version(%s);" % ( + Naming.type_dict_guard_temp, self_arg)) + code.putln("#endif") + func_node_temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True) self.func_node.set_cname(func_node_temp) # need to get attribute manually--scope would return cdef method @@ -4395,48 +4395,48 @@ class OverrideCheckNode(StatNode): code.putln("%s = __Pyx_PyObject_GetAttrStr(%s, %s); %s" % ( func_node_temp, self_arg, interned_attr_cname, err)) code.put_gotref(func_node_temp) - + is_builtin_function_or_method = "PyCFunction_Check(%s)" % func_node_temp - is_overridden = "(PyCFunction_GET_FUNCTION(%s) != (PyCFunction)(void*)%s)" % ( + is_overridden = "(PyCFunction_GET_FUNCTION(%s) != (PyCFunction)(void*)%s)" % ( func_node_temp, self.py_func.entry.func_cname) code.putln("if (!%s || %s) {" % (is_builtin_function_or_method, is_overridden)) self.body.generate_execution_code(code) code.putln("}") - - # NOTE: it's not 100% sure that we catch the exact versions here that were used for the lookup, - # but it is very unlikely that the versions change during lookup, and the type dict safe guard - # should increase the chance of detecting such a case. - code.putln("#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS") - code.putln("%s = __Pyx_get_tp_dict_version(%s);" % ( - Naming.tp_dict_version_temp, self_arg)) - code.putln("%s = __Pyx_get_object_dict_version(%s);" % ( - Naming.obj_dict_version_temp, self_arg)) - # Safety check that the type dict didn't change during the lookup. Since CPython looks up the - # attribute (descriptor) first in the type dict and then in the instance dict or through the - # descriptor, the only really far-away lookup when we get here is one in the type dict. So we - # double check the type dict version before and afterwards to guard against later changes of - # the type dict during the lookup process. - code.putln("if (unlikely(%s != %s)) {" % ( - Naming.type_dict_guard_temp, Naming.tp_dict_version_temp)) - code.putln("%s = %s = __PYX_DICT_VERSION_INIT;" % ( - Naming.tp_dict_version_temp, Naming.obj_dict_version_temp)) - code.putln("}") - code.putln("#endif") - + + # NOTE: it's not 100% sure that we catch the exact versions here that were used for the lookup, + # but it is very unlikely that the versions change during lookup, and the type dict safe guard + # should increase the chance of detecting such a case. + code.putln("#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS") + code.putln("%s = __Pyx_get_tp_dict_version(%s);" % ( + Naming.tp_dict_version_temp, self_arg)) + code.putln("%s = __Pyx_get_object_dict_version(%s);" % ( + Naming.obj_dict_version_temp, self_arg)) + # Safety check that the type dict didn't change during the lookup. Since CPython looks up the + # attribute (descriptor) first in the type dict and then in the instance dict or through the + # descriptor, the only really far-away lookup when we get here is one in the type dict. So we + # double check the type dict version before and afterwards to guard against later changes of + # the type dict during the lookup process. + code.putln("if (unlikely(%s != %s)) {" % ( + Naming.type_dict_guard_temp, Naming.tp_dict_version_temp)) + code.putln("%s = %s = __PYX_DICT_VERSION_INIT;" % ( + Naming.tp_dict_version_temp, Naming.obj_dict_version_temp)) + code.putln("}") + code.putln("#endif") + code.put_decref_clear(func_node_temp, PyrexTypes.py_object_type) code.funcstate.release_temp(func_node_temp) - - code.putln("#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS") + + code.putln("#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS") + code.putln("}") + code.putln("#endif") + code.putln("}") - code.putln("#endif") - code.putln("}") - - + class ClassDefNode(StatNode, BlockNode): pass - + class PyClassDefNode(ClassDefNode): # A Python class definition. # @@ -4462,7 +4462,7 @@ class PyClassDefNode(ClassDefNode): mkw = None def __init__(self, pos, name, bases, doc, body, decorators=None, - keyword_args=None, force_py3_semantics=False): + keyword_args=None, force_py3_semantics=False): StatNode.__init__(self, pos) self.name = name self.doc = doc @@ -4477,30 +4477,30 @@ class PyClassDefNode(ClassDefNode): doc_node = None allow_py2_metaclass = not force_py3_semantics - if keyword_args: + if keyword_args: allow_py2_metaclass = False self.is_py3_style_class = True - if keyword_args.is_dict_literal: - if keyword_args.key_value_pairs: - for i, item in list(enumerate(keyword_args.key_value_pairs))[::-1]: - if item.key.value == 'metaclass': - if self.metaclass is not None: - error(item.pos, "keyword argument 'metaclass' passed multiple times") - # special case: we already know the metaclass, - # so we don't need to do the "build kwargs, - # find metaclass" dance at runtime - self.metaclass = item.value - del keyword_args.key_value_pairs[i] - self.mkw = keyword_args - else: - assert self.metaclass is not None + if keyword_args.is_dict_literal: + if keyword_args.key_value_pairs: + for i, item in list(enumerate(keyword_args.key_value_pairs))[::-1]: + if item.key.value == 'metaclass': + if self.metaclass is not None: + error(item.pos, "keyword argument 'metaclass' passed multiple times") + # special case: we already know the metaclass, + # so we don't need to do the "build kwargs, + # find metaclass" dance at runtime + self.metaclass = item.value + del keyword_args.key_value_pairs[i] + self.mkw = keyword_args + else: + assert self.metaclass is not None else: - # MergedDictNode - self.mkw = ExprNodes.ProxyNode(keyword_args) + # MergedDictNode + self.mkw = ExprNodes.ProxyNode(keyword_args) if force_py3_semantics or self.bases or self.mkw or self.metaclass: if self.metaclass is None: - if keyword_args and not keyword_args.is_dict_literal: + if keyword_args and not keyword_args.is_dict_literal: # **kwargs may contain 'metaclass' arg mkdict = self.mkw else: @@ -4541,20 +4541,20 @@ class PyClassDefNode(ClassDefNode): from . import ExprNodes return CClassDefNode(self.pos, - visibility='private', - module_name=None, - class_name=self.name, + visibility='private', + module_name=None, + class_name=self.name, bases=self.bases or ExprNodes.TupleNode(self.pos, args=[]), - decorators=self.decorators, - body=self.body, - in_pxd=False, - doc=self.doc) + decorators=self.decorators, + body=self.body, + in_pxd=False, + doc=self.doc) def create_scope(self, env): genv = env while genv.is_py_class_scope or genv.is_c_class_scope: genv = genv.outer_scope - cenv = self.scope = PyClassScope(name=self.name, outer_scope=genv) + cenv = self.scope = PyClassScope(name=self.name, outer_scope=genv) return cenv def analyse_declarations(self, env): @@ -4564,8 +4564,8 @@ class PyClassDefNode(ClassDefNode): for decorator in self.decorators[::-1]: class_result = SimpleCallNode( decorator.pos, - function=decorator.decorator, - args=[class_result]) + function=decorator.decorator, + args=[class_result]) self.decorators = None self.class_result = class_result if self.bases: @@ -4599,7 +4599,7 @@ class PyClassDefNode(ClassDefNode): self.body.generate_function_definitions(self.scope, code) def generate_execution_code(self, code): - code.mark_pos(self.pos) + code.mark_pos(self.pos) code.pyclass_stack.append(self) cenv = self.scope if self.bases: @@ -4641,7 +4641,7 @@ class PyClassDefNode(ClassDefNode): self.bases.free_temps(code) code.pyclass_stack.pop() - + class CClassDefNode(ClassDefNode): # An extension type definition. # @@ -4654,7 +4654,7 @@ class CClassDefNode(ClassDefNode): # bases TupleNode Base class(es) # objstruct_name string or None Specified C name of object struct # typeobj_name string or None Specified C name of type object - # check_size 'warn', 'error', 'ignore' What to do if tp_basicsize does not match + # check_size 'warn', 'error', 'ignore' What to do if tp_basicsize does not match # in_pxd boolean Is in a .pxd file # decorators [DecoratorNode] list of decorators or None # doc string or None @@ -4671,7 +4671,7 @@ class CClassDefNode(ClassDefNode): api = False objstruct_name = None typeobj_name = None - check_size = None + check_size = None decorators = None shadow = False @@ -4697,20 +4697,20 @@ class CClassDefNode(ClassDefNode): home_scope = env self.entry = home_scope.declare_c_class( - name=self.class_name, - pos=self.pos, - defining=0, - implementing=0, - module_name=self.module_name, - base_type=None, - objstruct_cname=self.objstruct_name, - typeobj_cname=self.typeobj_name, - visibility=self.visibility, - typedef_flag=self.typedef_flag, - check_size = self.check_size, - api=self.api, - buffer_defaults=self.buffer_defaults(env), - shadow=self.shadow) + name=self.class_name, + pos=self.pos, + defining=0, + implementing=0, + module_name=self.module_name, + base_type=None, + objstruct_cname=self.objstruct_name, + typeobj_cname=self.typeobj_name, + visibility=self.visibility, + typedef_flag=self.typedef_flag, + check_size = self.check_size, + api=self.api, + buffer_defaults=self.buffer_defaults(env), + shadow=self.shadow) def analyse_declarations(self, env): #print "CClassDefNode.analyse_declarations:", self.class_name @@ -4718,9 +4718,9 @@ class CClassDefNode(ClassDefNode): #print "...module_name =", self.module_name if env.in_cinclude and not self.objstruct_name: - error(self.pos, "Object struct name specification required for C class defined in 'extern from' block") + error(self.pos, "Object struct name specification required for C class defined in 'extern from' block") if self.decorators: - error(self.pos, "Decorators not allowed on cdef classes (used on type '%s')" % self.class_name) + error(self.pos, "Decorators not allowed on cdef classes (used on type '%s')" % self.class_name) self.base_type = None # Now that module imports are cached, we need to # import the modules for extern classes. @@ -4780,25 +4780,25 @@ class CClassDefNode(ClassDefNode): if self.visibility == 'extern': if (self.module_name == '__builtin__' and - self.class_name in Builtin.builtin_types and - env.qualified_name[:8] != 'cpython.'): # allow overloaded names for cimporting from cpython + self.class_name in Builtin.builtin_types and + env.qualified_name[:8] != 'cpython.'): # allow overloaded names for cimporting from cpython warning(self.pos, "%s already a builtin Cython type" % self.class_name, 1) self.entry = home_scope.declare_c_class( - name=self.class_name, - pos=self.pos, - defining=has_body and self.in_pxd, - implementing=has_body and not self.in_pxd, - module_name=self.module_name, - base_type=self.base_type, - objstruct_cname=self.objstruct_name, - typeobj_cname=self.typeobj_name, - check_size=self.check_size, - visibility=self.visibility, - typedef_flag=self.typedef_flag, - api=self.api, - buffer_defaults=self.buffer_defaults(env), - shadow=self.shadow) + name=self.class_name, + pos=self.pos, + defining=has_body and self.in_pxd, + implementing=has_body and not self.in_pxd, + module_name=self.module_name, + base_type=self.base_type, + objstruct_cname=self.objstruct_name, + typeobj_cname=self.typeobj_name, + check_size=self.check_size, + visibility=self.visibility, + typedef_flag=self.typedef_flag, + api=self.api, + buffer_defaults=self.buffer_defaults(env), + shadow=self.shadow) if self.shadow: home_scope.lookup(self.class_name).as_variable = self.entry @@ -4813,15 +4813,15 @@ class CClassDefNode(ClassDefNode): if has_body: self.body.analyse_declarations(scope) - dict_entry = self.scope.lookup_here("__dict__") - if dict_entry and dict_entry.is_variable and (not scope.defined and not scope.implemented): - dict_entry.getter_cname = self.scope.mangle_internal("__dict__getter") - self.scope.declare_property("__dict__", dict_entry.doc, dict_entry.pos) + dict_entry = self.scope.lookup_here("__dict__") + if dict_entry and dict_entry.is_variable and (not scope.defined and not scope.implemented): + dict_entry.getter_cname = self.scope.mangle_internal("__dict__getter") + self.scope.declare_property("__dict__", dict_entry.doc, dict_entry.pos) if self.in_pxd: scope.defined = 1 else: scope.implemented = 1 - + if len(self.bases.args) > 1: if not has_body or self.in_pxd: error(self.bases.args[1].pos, "Only declare first base in declaration.") @@ -4865,7 +4865,7 @@ class CClassDefNode(ClassDefNode): def generate_execution_code(self, code): # This is needed to generate evaluation code for # default values of method arguments. - code.mark_pos(self.pos) + code.mark_pos(self.pos) if self.body: self.body.generate_execution_code(code) if not self.entry.type.early_init: @@ -4922,10 +4922,10 @@ class CClassDefNode(ClassDefNode): code.error_goto(entry.pos))) # Don't inherit tp_print from builtin types, restoring the # behavior of using tp_repr or tp_str instead. - # ("tp_print" was renamed to "tp_vectorcall_offset" in Py3.8b1) - code.putln("#if PY_VERSION_HEX < 0x030800B1") + # ("tp_print" was renamed to "tp_vectorcall_offset" in Py3.8b1) + code.putln("#if PY_VERSION_HEX < 0x030800B1") code.putln("%s.tp_print = 0;" % typeobj_cname) - code.putln("#endif") + code.putln("#endif") # Use specialised attribute lookup for types with generic lookup but no instance dict. getattr_slot_func = TypeSlots.get_slot_code_by_name(scope, 'tp_getattro') @@ -4993,14 +4993,14 @@ class CClassDefNode(ClassDefNode): code.putln("if (__Pyx_MergeVtables(&%s) < 0) %s" % ( typeobj_cname, code.error_goto(entry.pos))) - if not type.scope.is_internal and not type.scope.directives.get('internal'): + if not type.scope.is_internal and not type.scope.directives.get('internal'): # scope.is_internal is set for types defined by # Cython (such as closures), the 'internal' # directive is set by users code.putln( - 'if (PyObject_SetAttr(%s, %s, (PyObject *)&%s) < 0) %s' % ( + 'if (PyObject_SetAttr(%s, %s, (PyObject *)&%s) < 0) %s' % ( Naming.module_cname, - code.intern_identifier(scope.class_name), + code.intern_identifier(scope.class_name), typeobj_cname, code.error_goto(entry.pos))) weakref_entry = scope.lookup_here("__weakref__") if not scope.is_closure_class_scope else None @@ -5127,7 +5127,7 @@ class ExprStatNode(StatNode): if type is None: error(type_node.pos, "Unknown type") else: - env.declare_var(var.value, type, var.pos, is_cdef=True) + env.declare_var(var.value, type, var.pos, is_cdef=True) self.__class__ = PassStatNode elif getattr(expr, 'annotation', None) is not None: if expr.is_name: @@ -5139,7 +5139,7 @@ class ExprStatNode(StatNode): self.__class__ = PassStatNode def analyse_expressions(self, env): - self.expr.result_is_used = False # hint that .result() may safely be left empty + self.expr.result_is_used = False # hint that .result() may safely be left empty self.expr = self.expr.analyse_expressions(env) # Repeat in case of node replacement. self.expr.result_is_used = False # hint that .result() may safely be left empty @@ -5152,7 +5152,7 @@ class ExprStatNode(StatNode): gil_message = "Discarding owned Python object" def generate_execution_code(self, code): - code.mark_pos(self.pos) + code.mark_pos(self.pos) self.expr.result_is_used = False # hint that .result() may safely be left empty self.expr.generate_evaluation_code(code) if not self.expr.is_temp and self.expr.result(): @@ -5181,7 +5181,7 @@ class AssignmentNode(StatNode): def analyse_expressions(self, env): node = self.analyse_types(env) - if isinstance(node, AssignmentNode) and not isinstance(node, ParallelAssignmentNode): + if isinstance(node, AssignmentNode) and not isinstance(node, ParallelAssignmentNode): if node.rhs.type.is_ptr and node.rhs.is_ephemeral(): error(self.pos, "Storing unsafe C derivative of temporary Python reference") return node @@ -5191,7 +5191,7 @@ class AssignmentNode(StatNode): # self.analyse_expressions_2(env) def generate_execution_code(self, code): - code.mark_pos(self.pos) + code.mark_pos(self.pos) self.generate_rhs_evaluation_code(code) self.generate_assignment_code(code) @@ -5201,16 +5201,16 @@ class SingleAssignmentNode(AssignmentNode): # # a = b # - # lhs ExprNode Left hand side - # rhs ExprNode Right hand side - # first bool Is this guaranteed the first assignment to lhs? - # is_overloaded_assignment bool Is this assignment done via an overloaded operator= - # exception_check - # exception_value + # lhs ExprNode Left hand side + # rhs ExprNode Right hand side + # first bool Is this guaranteed the first assignment to lhs? + # is_overloaded_assignment bool Is this assignment done via an overloaded operator= + # exception_check + # exception_value child_attrs = ["lhs", "rhs"] first = False - is_overloaded_assignment = False + is_overloaded_assignment = False declaration_only = False def analyse_declarations(self, env): @@ -5222,17 +5222,17 @@ class SingleAssignmentNode(AssignmentNode): if func_name: args, kwds = self.rhs.explicit_args_kwds() if func_name in ['declare', 'typedef']: - if len(args) > 2: - error(args[2].pos, "Invalid positional argument.") + if len(args) > 2: + error(args[2].pos, "Invalid positional argument.") return - if kwds is not None: - kwdict = kwds.compile_time_value(None) - if func_name == 'typedef' or 'visibility' not in kwdict: - error(kwds.pos, "Invalid keyword argument.") - return - visibility = kwdict['visibility'] - else: - visibility = 'private' + if kwds is not None: + kwdict = kwds.compile_time_value(None) + if func_name == 'typedef' or 'visibility' not in kwdict: + error(kwds.pos, "Invalid keyword argument.") + return + visibility = kwdict['visibility'] + else: + visibility = 'private' type = args[0].analyse_as_type(env) if type is None: error(args[0].pos, "Unknown type") @@ -5247,7 +5247,7 @@ class SingleAssignmentNode(AssignmentNode): error(lhs.pos, "Invalid declaration") return for var, pos in vars: - env.declare_var(var, type, pos, is_cdef=True, visibility=visibility) + env.declare_var(var, type, pos, is_cdef=True, visibility=visibility) if len(args) == 2: # we have a value self.rhs = args[1] @@ -5289,7 +5289,7 @@ class SingleAssignmentNode(AssignmentNode): "fused_type does not take keyword arguments") fusednode = FusedTypeNode(self.rhs.pos, - name=self.lhs.name, types=args) + name=self.lhs.name, types=args) fusednode.analyse_declarations(env) if self.declaration_only: @@ -5297,44 +5297,44 @@ class SingleAssignmentNode(AssignmentNode): else: self.lhs.analyse_target_declaration(env) - def analyse_types(self, env, use_temp=0): + def analyse_types(self, env, use_temp=0): from . import ExprNodes self.rhs = self.rhs.analyse_types(env) - - unrolled_assignment = self.unroll_rhs(env) - if unrolled_assignment: - return unrolled_assignment - + + unrolled_assignment = self.unroll_rhs(env) + if unrolled_assignment: + return unrolled_assignment + self.lhs = self.lhs.analyse_target_types(env) self.lhs.gil_assignment_check(env) - unrolled_assignment = self.unroll_lhs(env) - if unrolled_assignment: - return unrolled_assignment - - if isinstance(self.lhs, ExprNodes.MemoryViewIndexNode): - self.lhs.analyse_broadcast_operation(self.rhs) - self.lhs = self.lhs.analyse_as_memview_scalar_assignment(self.rhs) - elif self.lhs.type.is_array: - if not isinstance(self.lhs, ExprNodes.SliceIndexNode): - # cannot assign to C array, only to its full slice - self.lhs = ExprNodes.SliceIndexNode(self.lhs.pos, base=self.lhs, start=None, stop=None) - self.lhs = self.lhs.analyse_target_types(env) - - if self.lhs.type.is_cpp_class: - op = env.lookup_operator_for_types(self.pos, '=', [self.lhs.type, self.rhs.type]) - if op: - rhs = self.rhs - self.is_overloaded_assignment = True - self.exception_check = op.type.exception_check - self.exception_value = op.type.exception_value - if self.exception_check == '+' and self.exception_value is None: - env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp")) - else: - rhs = self.rhs.coerce_to(self.lhs.type, env) - else: - rhs = self.rhs.coerce_to(self.lhs.type, env) - + unrolled_assignment = self.unroll_lhs(env) + if unrolled_assignment: + return unrolled_assignment + + if isinstance(self.lhs, ExprNodes.MemoryViewIndexNode): + self.lhs.analyse_broadcast_operation(self.rhs) + self.lhs = self.lhs.analyse_as_memview_scalar_assignment(self.rhs) + elif self.lhs.type.is_array: + if not isinstance(self.lhs, ExprNodes.SliceIndexNode): + # cannot assign to C array, only to its full slice + self.lhs = ExprNodes.SliceIndexNode(self.lhs.pos, base=self.lhs, start=None, stop=None) + self.lhs = self.lhs.analyse_target_types(env) + + if self.lhs.type.is_cpp_class: + op = env.lookup_operator_for_types(self.pos, '=', [self.lhs.type, self.rhs.type]) + if op: + rhs = self.rhs + self.is_overloaded_assignment = True + self.exception_check = op.type.exception_check + self.exception_value = op.type.exception_value + if self.exception_check == '+' and self.exception_value is None: + env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp")) + else: + rhs = self.rhs.coerce_to(self.lhs.type, env) + else: + rhs = self.rhs.coerce_to(self.lhs.type, env) + if use_temp or rhs.is_attribute or ( not rhs.is_name and not rhs.is_literal and rhs.type.is_pyobject): @@ -5345,152 +5345,152 @@ class SingleAssignmentNode(AssignmentNode): self.rhs = rhs return self - def unroll(self, node, target_size, env): - from . import ExprNodes, UtilNodes - - base = node - start_node = stop_node = step_node = check_node = None - - if node.type.is_ctuple: - slice_size = node.type.size - - elif node.type.is_ptr or node.type.is_array: - while isinstance(node, ExprNodes.SliceIndexNode) and not (node.start or node.stop): - base = node = node.base - if isinstance(node, ExprNodes.SliceIndexNode): - base = node.base - start_node = node.start - if start_node: - start_node = start_node.coerce_to(PyrexTypes.c_py_ssize_t_type, env) - stop_node = node.stop - if stop_node: - stop_node = stop_node.coerce_to(PyrexTypes.c_py_ssize_t_type, env) - else: - if node.type.is_array and node.type.size: - stop_node = ExprNodes.IntNode( - self.pos, value=str(node.type.size), - constant_result=(node.type.size if isinstance(node.type.size, _py_int_types) - else ExprNodes.constant_value_not_set)) - else: - error(self.pos, "C array iteration requires known end index") - return - step_node = None #node.step - if step_node: - step_node = step_node.coerce_to(PyrexTypes.c_py_ssize_t_type, env) - - # TODO: Factor out SliceIndexNode.generate_slice_guard_code() for use here. - def get_const(node, none_value): - if node is None: - return none_value - elif node.has_constant_result(): - return node.constant_result - else: - raise ValueError("Not a constant.") - - try: - slice_size = (get_const(stop_node, None) - get_const(start_node, 0)) / get_const(step_node, 1) - except ValueError: - error(self.pos, "C array assignment currently requires known endpoints") - return - - elif node.type.is_array: - slice_size = node.type.size - if not isinstance(slice_size, _py_int_types): - return # might still work when coercing to Python - else: - return - - else: - return - - if slice_size != target_size: - error(self.pos, "Assignment to/from slice of wrong length, expected %s, got %s" % ( - slice_size, target_size)) - return - - items = [] - base = UtilNodes.LetRefNode(base) - refs = [base] - if start_node and not start_node.is_literal: - start_node = UtilNodes.LetRefNode(start_node) - refs.append(start_node) - if stop_node and not stop_node.is_literal: - stop_node = UtilNodes.LetRefNode(stop_node) - refs.append(stop_node) - if step_node and not step_node.is_literal: - step_node = UtilNodes.LetRefNode(step_node) - refs.append(step_node) - - for ix in range(target_size): - ix_node = ExprNodes.IntNode(self.pos, value=str(ix), constant_result=ix, type=PyrexTypes.c_py_ssize_t_type) - if step_node is not None: - if step_node.has_constant_result(): - step_value = ix_node.constant_result * step_node.constant_result - ix_node = ExprNodes.IntNode(self.pos, value=str(step_value), constant_result=step_value) - else: - ix_node = ExprNodes.MulNode(self.pos, operator='*', operand1=step_node, operand2=ix_node) - if start_node is not None: - if start_node.has_constant_result() and ix_node.has_constant_result(): - index_value = ix_node.constant_result + start_node.constant_result - ix_node = ExprNodes.IntNode(self.pos, value=str(index_value), constant_result=index_value) - else: - ix_node = ExprNodes.AddNode( - self.pos, operator='+', operand1=start_node, operand2=ix_node) - items.append(ExprNodes.IndexNode(self.pos, base=base, index=ix_node.analyse_types(env))) - return check_node, refs, items - - def unroll_assignments(self, refs, check_node, lhs_list, rhs_list, env): - from . import UtilNodes - assignments = [] - for lhs, rhs in zip(lhs_list, rhs_list): - assignments.append(SingleAssignmentNode(self.pos, lhs=lhs, rhs=rhs, first=self.first)) - node = ParallelAssignmentNode(pos=self.pos, stats=assignments).analyse_expressions(env) - if check_node: - node = StatListNode(pos=self.pos, stats=[check_node, node]) - for ref in refs[::-1]: - node = UtilNodes.LetNode(ref, node) - return node - - def unroll_rhs(self, env): - from . import ExprNodes - if not isinstance(self.lhs, ExprNodes.TupleNode): - return - if any(arg.is_starred for arg in self.lhs.args): - return - - unrolled = self.unroll(self.rhs, len(self.lhs.args), env) - if not unrolled: - return - check_node, refs, rhs = unrolled - return self.unroll_assignments(refs, check_node, self.lhs.args, rhs, env) - - def unroll_lhs(self, env): - if self.lhs.type.is_ctuple: - # Handled directly. - return - from . import ExprNodes - if not isinstance(self.rhs, ExprNodes.TupleNode): - return - - unrolled = self.unroll(self.lhs, len(self.rhs.args), env) - if not unrolled: - return - check_node, refs, lhs = unrolled - return self.unroll_assignments(refs, check_node, lhs, self.rhs.args, env) - + def unroll(self, node, target_size, env): + from . import ExprNodes, UtilNodes + + base = node + start_node = stop_node = step_node = check_node = None + + if node.type.is_ctuple: + slice_size = node.type.size + + elif node.type.is_ptr or node.type.is_array: + while isinstance(node, ExprNodes.SliceIndexNode) and not (node.start or node.stop): + base = node = node.base + if isinstance(node, ExprNodes.SliceIndexNode): + base = node.base + start_node = node.start + if start_node: + start_node = start_node.coerce_to(PyrexTypes.c_py_ssize_t_type, env) + stop_node = node.stop + if stop_node: + stop_node = stop_node.coerce_to(PyrexTypes.c_py_ssize_t_type, env) + else: + if node.type.is_array and node.type.size: + stop_node = ExprNodes.IntNode( + self.pos, value=str(node.type.size), + constant_result=(node.type.size if isinstance(node.type.size, _py_int_types) + else ExprNodes.constant_value_not_set)) + else: + error(self.pos, "C array iteration requires known end index") + return + step_node = None #node.step + if step_node: + step_node = step_node.coerce_to(PyrexTypes.c_py_ssize_t_type, env) + + # TODO: Factor out SliceIndexNode.generate_slice_guard_code() for use here. + def get_const(node, none_value): + if node is None: + return none_value + elif node.has_constant_result(): + return node.constant_result + else: + raise ValueError("Not a constant.") + + try: + slice_size = (get_const(stop_node, None) - get_const(start_node, 0)) / get_const(step_node, 1) + except ValueError: + error(self.pos, "C array assignment currently requires known endpoints") + return + + elif node.type.is_array: + slice_size = node.type.size + if not isinstance(slice_size, _py_int_types): + return # might still work when coercing to Python + else: + return + + else: + return + + if slice_size != target_size: + error(self.pos, "Assignment to/from slice of wrong length, expected %s, got %s" % ( + slice_size, target_size)) + return + + items = [] + base = UtilNodes.LetRefNode(base) + refs = [base] + if start_node and not start_node.is_literal: + start_node = UtilNodes.LetRefNode(start_node) + refs.append(start_node) + if stop_node and not stop_node.is_literal: + stop_node = UtilNodes.LetRefNode(stop_node) + refs.append(stop_node) + if step_node and not step_node.is_literal: + step_node = UtilNodes.LetRefNode(step_node) + refs.append(step_node) + + for ix in range(target_size): + ix_node = ExprNodes.IntNode(self.pos, value=str(ix), constant_result=ix, type=PyrexTypes.c_py_ssize_t_type) + if step_node is not None: + if step_node.has_constant_result(): + step_value = ix_node.constant_result * step_node.constant_result + ix_node = ExprNodes.IntNode(self.pos, value=str(step_value), constant_result=step_value) + else: + ix_node = ExprNodes.MulNode(self.pos, operator='*', operand1=step_node, operand2=ix_node) + if start_node is not None: + if start_node.has_constant_result() and ix_node.has_constant_result(): + index_value = ix_node.constant_result + start_node.constant_result + ix_node = ExprNodes.IntNode(self.pos, value=str(index_value), constant_result=index_value) + else: + ix_node = ExprNodes.AddNode( + self.pos, operator='+', operand1=start_node, operand2=ix_node) + items.append(ExprNodes.IndexNode(self.pos, base=base, index=ix_node.analyse_types(env))) + return check_node, refs, items + + def unroll_assignments(self, refs, check_node, lhs_list, rhs_list, env): + from . import UtilNodes + assignments = [] + for lhs, rhs in zip(lhs_list, rhs_list): + assignments.append(SingleAssignmentNode(self.pos, lhs=lhs, rhs=rhs, first=self.first)) + node = ParallelAssignmentNode(pos=self.pos, stats=assignments).analyse_expressions(env) + if check_node: + node = StatListNode(pos=self.pos, stats=[check_node, node]) + for ref in refs[::-1]: + node = UtilNodes.LetNode(ref, node) + return node + + def unroll_rhs(self, env): + from . import ExprNodes + if not isinstance(self.lhs, ExprNodes.TupleNode): + return + if any(arg.is_starred for arg in self.lhs.args): + return + + unrolled = self.unroll(self.rhs, len(self.lhs.args), env) + if not unrolled: + return + check_node, refs, rhs = unrolled + return self.unroll_assignments(refs, check_node, self.lhs.args, rhs, env) + + def unroll_lhs(self, env): + if self.lhs.type.is_ctuple: + # Handled directly. + return + from . import ExprNodes + if not isinstance(self.rhs, ExprNodes.TupleNode): + return + + unrolled = self.unroll(self.lhs, len(self.rhs.args), env) + if not unrolled: + return + check_node, refs, lhs = unrolled + return self.unroll_assignments(refs, check_node, lhs, self.rhs.args, env) + def generate_rhs_evaluation_code(self, code): self.rhs.generate_evaluation_code(code) - def generate_assignment_code(self, code, overloaded_assignment=False): - if self.is_overloaded_assignment: - self.lhs.generate_assignment_code( - self.rhs, - code, - overloaded_assignment=self.is_overloaded_assignment, - exception_check=self.exception_check, - exception_value=self.exception_value) - else: - self.lhs.generate_assignment_code(self.rhs, code) + def generate_assignment_code(self, code, overloaded_assignment=False): + if self.is_overloaded_assignment: + self.lhs.generate_assignment_code( + self.rhs, + code, + overloaded_assignment=self.is_overloaded_assignment, + exception_check=self.exception_check, + exception_value=self.exception_value) + else: + self.lhs.generate_assignment_code(self.rhs, code) def generate_function_definitions(self, env, code): self.rhs.generate_function_definitions(env, code) @@ -5510,14 +5510,14 @@ class CascadedAssignmentNode(AssignmentNode): # # Used internally: # - # coerced_values [ExprNode] RHS coerced to all distinct LHS types - # cloned_values [ExprNode] cloned RHS value for each LHS - # assignment_overloads [Bool] If each assignment uses a C++ operator= + # coerced_values [ExprNode] RHS coerced to all distinct LHS types + # cloned_values [ExprNode] cloned RHS value for each LHS + # assignment_overloads [Bool] If each assignment uses a C++ operator= - child_attrs = ["lhs_list", "rhs", "coerced_values", "cloned_values"] - cloned_values = None + child_attrs = ["lhs_list", "rhs", "coerced_values", "cloned_values"] + cloned_values = None coerced_values = None - assignment_overloads = None + assignment_overloads = None def analyse_declarations(self, env): for lhs in self.lhs_list: @@ -5526,23 +5526,23 @@ class CascadedAssignmentNode(AssignmentNode): def analyse_types(self, env, use_temp=0): from .ExprNodes import CloneNode, ProxyNode - # collect distinct types used on the LHS + # collect distinct types used on the LHS lhs_types = set() - for i, lhs in enumerate(self.lhs_list): - lhs = self.lhs_list[i] = lhs.analyse_target_types(env) + for i, lhs in enumerate(self.lhs_list): + lhs = self.lhs_list[i] = lhs.analyse_target_types(env) lhs.gil_assignment_check(env) lhs_types.add(lhs.type) rhs = self.rhs.analyse_types(env) - # common special case: only one type needed on the LHS => coerce only once + # common special case: only one type needed on the LHS => coerce only once if len(lhs_types) == 1: - # Avoid coercion for overloaded assignment operators. - if next(iter(lhs_types)).is_cpp_class: - op = env.lookup_operator('=', [lhs, self.rhs]) - if not op: - rhs = rhs.coerce_to(lhs_types.pop(), env) - else: - rhs = rhs.coerce_to(lhs_types.pop(), env) + # Avoid coercion for overloaded assignment operators. + if next(iter(lhs_types)).is_cpp_class: + op = env.lookup_operator('=', [lhs, self.rhs]) + if not op: + rhs = rhs.coerce_to(lhs_types.pop(), env) + else: + rhs = rhs.coerce_to(lhs_types.pop(), env) if not rhs.is_name and not rhs.is_literal and ( use_temp or rhs.is_attribute or rhs.type.is_pyobject): @@ -5551,42 +5551,42 @@ class CascadedAssignmentNode(AssignmentNode): rhs = rhs.coerce_to_simple(env) self.rhs = ProxyNode(rhs) if rhs.is_temp else rhs - # clone RHS and coerce it to all distinct LHS types + # clone RHS and coerce it to all distinct LHS types self.coerced_values = [] coerced_values = {} - self.assignment_overloads = [] + self.assignment_overloads = [] for lhs in self.lhs_list: - overloaded = lhs.type.is_cpp_class and env.lookup_operator('=', [lhs, self.rhs]) - self.assignment_overloads.append(overloaded) + overloaded = lhs.type.is_cpp_class and env.lookup_operator('=', [lhs, self.rhs]) + self.assignment_overloads.append(overloaded) if lhs.type not in coerced_values and lhs.type != rhs.type: - rhs = CloneNode(self.rhs) - if not overloaded: - rhs = rhs.coerce_to(lhs.type, env) + rhs = CloneNode(self.rhs) + if not overloaded: + rhs = rhs.coerce_to(lhs.type, env) self.coerced_values.append(rhs) coerced_values[lhs.type] = rhs - # clone coerced values for all LHS assignments - self.cloned_values = [] + # clone coerced values for all LHS assignments + self.cloned_values = [] for lhs in self.lhs_list: rhs = coerced_values.get(lhs.type, self.rhs) - self.cloned_values.append(CloneNode(rhs)) + self.cloned_values.append(CloneNode(rhs)) return self def generate_rhs_evaluation_code(self, code): self.rhs.generate_evaluation_code(code) - def generate_assignment_code(self, code, overloaded_assignment=False): - # prepare all coercions + def generate_assignment_code(self, code, overloaded_assignment=False): + # prepare all coercions for rhs in self.coerced_values: rhs.generate_evaluation_code(code) - # assign clones to LHS - for lhs, rhs, overload in zip(self.lhs_list, self.cloned_values, self.assignment_overloads): + # assign clones to LHS + for lhs, rhs, overload in zip(self.lhs_list, self.cloned_values, self.assignment_overloads): rhs.generate_evaluation_code(code) - lhs.generate_assignment_code(rhs, code, overloaded_assignment=overload) - # dispose of coerced values and original RHS - for rhs_value in self.coerced_values: - rhs_value.generate_disposal_code(code) - rhs_value.free_temps(code) + lhs.generate_assignment_code(rhs, code, overloaded_assignment=overload) + # dispose of coerced values and original RHS + for rhs_value in self.coerced_values: + rhs_value.generate_disposal_code(code) + rhs_value.free_temps(code) self.rhs.generate_disposal_code(code) self.rhs.free_temps(code) @@ -5596,7 +5596,7 @@ class CascadedAssignmentNode(AssignmentNode): def annotate(self, code): for rhs in self.coerced_values: rhs.annotate(code) - for lhs, rhs in zip(self.lhs_list, self.cloned_values): + for lhs, rhs in zip(self.lhs_list, self.cloned_values): lhs.annotate(code) rhs.annotate(code) self.rhs.annotate(code) @@ -5623,18 +5623,18 @@ class ParallelAssignmentNode(AssignmentNode): stat.analyse_declarations(env) def analyse_expressions(self, env): - self.stats = [stat.analyse_types(env, use_temp=1) - for stat in self.stats] + self.stats = [stat.analyse_types(env, use_temp=1) + for stat in self.stats] return self # def analyse_expressions(self, env): # for stat in self.stats: -# stat.analyse_expressions_1(env, use_temp=1) +# stat.analyse_expressions_1(env, use_temp=1) # for stat in self.stats: # stat.analyse_expressions_2(env) def generate_execution_code(self, code): - code.mark_pos(self.pos) + code.mark_pos(self.pos) for stat in self.stats: stat.generate_rhs_evaluation_code(code) for stat in self.stats: @@ -5677,7 +5677,7 @@ class InPlaceAssignmentNode(AssignmentNode): self.lhs = self.lhs.analyse_target_types(env) # When assigning to a fully indexed buffer or memoryview, coerce the rhs - if self.lhs.is_memview_index or self.lhs.is_buffer_access: + if self.lhs.is_memview_index or self.lhs.is_buffer_access: self.rhs = self.rhs.coerce_to(self.lhs.type, env) elif self.lhs.type.is_string and self.operator in '+-': # use pointer arithmetic for char* LHS instead of string concat @@ -5685,31 +5685,31 @@ class InPlaceAssignmentNode(AssignmentNode): return self def generate_execution_code(self, code): - code.mark_pos(self.pos) - lhs, rhs = self.lhs, self.rhs - rhs.generate_evaluation_code(code) - lhs.generate_subexpr_evaluation_code(code) + code.mark_pos(self.pos) + lhs, rhs = self.lhs, self.rhs + rhs.generate_evaluation_code(code) + lhs.generate_subexpr_evaluation_code(code) c_op = self.operator if c_op == "//": c_op = "/" elif c_op == "**": error(self.pos, "No C inplace power operator") - if lhs.is_buffer_access or lhs.is_memview_index: - if lhs.type.is_pyobject: + if lhs.is_buffer_access or lhs.is_memview_index: + if lhs.type.is_pyobject: error(self.pos, "In-place operators not allowed on object buffers in this release.") - if c_op in ('/', '%') and lhs.type.is_int and not code.globalstate.directives['cdivision']: + if c_op in ('/', '%') and lhs.type.is_int and not code.globalstate.directives['cdivision']: error(self.pos, "In-place non-c divide operators not allowed on int buffers.") - lhs.generate_buffer_setitem_code(rhs, code, c_op) - elif lhs.is_memview_slice: - error(self.pos, "Inplace operators not supported on memoryview slices") + lhs.generate_buffer_setitem_code(rhs, code, c_op) + elif lhs.is_memview_slice: + error(self.pos, "Inplace operators not supported on memoryview slices") else: # C++ # TODO: make sure overload is declared - code.putln("%s %s= %s;" % (lhs.result(), c_op, rhs.result())) - lhs.generate_subexpr_disposal_code(code) - lhs.free_subexpr_temps(code) - rhs.generate_disposal_code(code) - rhs.free_temps(code) + code.putln("%s %s= %s;" % (lhs.result(), c_op, rhs.result())) + lhs.generate_subexpr_disposal_code(code) + lhs.free_subexpr_temps(code) + rhs.generate_disposal_code(code) + rhs.free_temps(code) def annotate(self, code): self.lhs.annotate(code) @@ -5744,7 +5744,7 @@ class PrintStatNode(StatNode): gil_message = "Python print statement" def generate_execution_code(self, code): - code.mark_pos(self.pos) + code.mark_pos(self.pos) if self.stream: self.stream.generate_evaluation_code(code) stream_result = self.stream.py_result() @@ -5806,14 +5806,14 @@ class ExecStatNode(StatNode): gil_message = "Python exec statement" def generate_execution_code(self, code): - code.mark_pos(self.pos) + code.mark_pos(self.pos) args = [] for arg in self.args: arg.generate_evaluation_code(code) - args.append(arg.py_result()) + args.append(arg.py_result()) args = tuple(args + ['0', '0'][:3-len(args)]) temp_result = code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=True) - code.putln("%s = __Pyx_PyExec3(%s, %s, %s);" % ((temp_result,) + args)) + code.putln("%s = __Pyx_PyExec3(%s, %s, %s);" % ((temp_result,) + args)) for arg in self.args: arg.generate_disposal_code(code) arg.free_temps(code) @@ -5843,7 +5843,7 @@ class DelStatNode(StatNode): def analyse_expressions(self, env): for i, arg in enumerate(self.args): arg = self.args[i] = arg.analyse_target_expression(env, None) - if arg.type.is_pyobject or (arg.is_name and arg.type.is_memoryviewslice): + if arg.type.is_pyobject or (arg.is_name and arg.type.is_memoryviewslice): if arg.is_name and arg.entry.is_cglobal: error(arg.pos, "Deletion of global C variable") elif arg.type.is_ptr and arg.type.base_type.is_cpp_class: @@ -5865,7 +5865,7 @@ class DelStatNode(StatNode): gil_message = "Deleting Python object" def generate_execution_code(self, code): - code.mark_pos(self.pos) + code.mark_pos(self.pos) for arg in self.args: if (arg.type.is_pyobject or arg.type.is_memoryviewslice or @@ -5915,7 +5915,7 @@ class BreakStatNode(StatNode): return self def generate_execution_code(self, code): - code.mark_pos(self.pos) + code.mark_pos(self.pos) if not code.break_label: error(self.pos, "break statement not inside loop") else: @@ -5931,11 +5931,11 @@ class ContinueStatNode(StatNode): return self def generate_execution_code(self, code): - if not code.continue_label: - error(self.pos, "continue statement not inside loop") - return - code.mark_pos(self.pos) - code.put_goto(code.continue_label) + if not code.continue_label: + error(self.pos, "continue statement not inside loop") + return + code.mark_pos(self.pos) + code.put_goto(code.continue_label) class ReturnStatNode(StatNode): @@ -5965,14 +5965,14 @@ class ReturnStatNode(StatNode): error(self.pos, "Return with value in async generator") self.value = self.value.analyse_types(env) if return_type.is_void or return_type.is_returncode: - error(self.value.pos, "Return with value in void function") + error(self.value.pos, "Return with value in void function") else: self.value = self.value.coerce_to(env.return_type, env) else: if (not return_type.is_void - and not return_type.is_pyobject - and not return_type.is_returncode): - error(self.pos, "Return value required") + and not return_type.is_pyobject + and not return_type.is_returncode): + error(self.pos, "Return value required") return self def nogil_check(self, env): @@ -5999,38 +5999,38 @@ class ReturnStatNode(StatNode): if self.return_type.is_memoryviewslice: from . import MemoryView MemoryView.put_acquire_memoryviewslice( - lhs_cname=Naming.retval_cname, - lhs_type=self.return_type, + lhs_cname=Naming.retval_cname, + lhs_type=self.return_type, lhs_pos=value.pos, rhs=value, - code=code, - have_gil=self.in_nogil_context) + code=code, + have_gil=self.in_nogil_context) value.generate_post_assignment_code(code) elif self.in_generator: # return value == raise StopIteration(value), but uncatchable - code.globalstate.use_utility_code( - UtilityCode.load_cached("ReturnWithStopIteration", "Coroutine.c")) - code.putln("%s = NULL; __Pyx_ReturnWithStopIteration(%s);" % ( - Naming.retval_cname, + code.globalstate.use_utility_code( + UtilityCode.load_cached("ReturnWithStopIteration", "Coroutine.c")) + code.putln("%s = NULL; __Pyx_ReturnWithStopIteration(%s);" % ( + Naming.retval_cname, value.py_result())) value.generate_disposal_code(code) else: value.make_owned_reference(code) - code.putln("%s = %s;" % ( - Naming.retval_cname, + code.putln("%s = %s;" % ( + Naming.retval_cname, value.result_as(self.return_type))) value.generate_post_assignment_code(code) value.free_temps(code) else: if self.return_type.is_pyobject: - if self.in_generator: + if self.in_generator: if self.in_async_gen: code.globalstate.use_utility_code( UtilityCode.load_cached("StopAsyncIteration", "Coroutine.c")) code.put("PyErr_SetNone(__Pyx_PyExc_StopAsyncIteration); ") - code.putln("%s = NULL;" % Naming.retval_cname) - else: - code.put_init_to_py_none(Naming.retval_cname, self.return_type) + code.putln("%s = NULL;" % Naming.retval_cname) + else: + code.put_init_to_py_none(Naming.retval_cname, self.return_type) elif self.return_type.is_returncode: self.put_return(code, self.return_type.default_value) @@ -6083,8 +6083,8 @@ class RaiseStatNode(StatNode): exc = self.exc_type from . import ExprNodes if (isinstance(exc, ExprNodes.SimpleCallNode) and - not (exc.args or (exc.arg_tuple is not None and exc.arg_tuple.args))): - exc = exc.function # extract the exception type + not (exc.args or (exc.arg_tuple is not None and exc.arg_tuple.args))): + exc = exc.function # extract the exception type if exc.is_name and exc.entry.is_builtin: self.builtin_exc_name = exc.name if self.builtin_exc_name == 'MemoryError': @@ -6095,7 +6095,7 @@ class RaiseStatNode(StatNode): gil_message = "Raising exception" def generate_execution_code(self, code): - code.mark_pos(self.pos) + code.mark_pos(self.pos) if self.builtin_exc_name == 'MemoryError': code.putln('PyErr_NoMemory(); %s' % code.error_goto(self.pos)) return @@ -6169,7 +6169,7 @@ class ReraiseStatNode(StatNode): gil_message = "Raising exception" def generate_execution_code(self, code): - code.mark_pos(self.pos) + code.mark_pos(self.pos) vars = code.funcstate.exc_vars if vars: code.globalstate.use_utility_code(restore_exception_utility_code) @@ -6177,7 +6177,7 @@ class ReraiseStatNode(StatNode): code.put_giveref(vars[1]) # fresh exceptions may not have a traceback yet (-> finally!) code.put_xgiveref(vars[2]) - code.putln("__Pyx_ErrRestoreWithState(%s, %s, %s);" % tuple(vars)) + code.putln("__Pyx_ErrRestoreWithState(%s, %s, %s);" % tuple(vars)) for varname in vars: code.put("%s = 0; " % varname) code.putln() @@ -6203,7 +6203,7 @@ class AssertStatNode(StatNode): # prevent tuple values from being interpreted as argument value tuples from .ExprNodes import TupleNode value = TupleNode(value.pos, args=[value], slow=True) - self.value = value.analyse_types(env, skip_children=True).coerce_to_pyobject(env) + self.value = value.analyse_types(env, skip_children=True).coerce_to_pyobject(env) else: self.value = value.coerce_to_pyobject(env) return self @@ -6214,21 +6214,21 @@ class AssertStatNode(StatNode): def generate_execution_code(self, code): code.putln("#ifndef CYTHON_WITHOUT_ASSERTIONS") code.putln("if (unlikely(!Py_OptimizeFlag)) {") - code.mark_pos(self.pos) + code.mark_pos(self.pos) self.cond.generate_evaluation_code(code) code.putln( - "if (unlikely(!%s)) {" % self.cond.result()) + "if (unlikely(!%s)) {" % self.cond.result()) if self.value: self.value.generate_evaluation_code(code) code.putln( - "PyErr_SetObject(PyExc_AssertionError, %s);" % self.value.py_result()) + "PyErr_SetObject(PyExc_AssertionError, %s);" % self.value.py_result()) self.value.generate_disposal_code(code) self.value.free_temps(code) else: code.putln( "PyErr_SetNone(PyExc_AssertionError);") code.putln( - code.error_goto(self.pos)) + code.error_goto(self.pos)) code.putln( "}") self.cond.generate_disposal_code(code) @@ -6263,7 +6263,7 @@ class IfStatNode(StatNode): self.else_clause.analyse_declarations(env) def analyse_expressions(self, env): - self.if_clauses = [if_clause.analyse_expressions(env) for if_clause in self.if_clauses] + self.if_clauses = [if_clause.analyse_expressions(env) for if_clause in self.if_clauses] if self.else_clause: self.else_clause = self.else_clause.analyse_expressions(env) return self @@ -6271,17 +6271,17 @@ class IfStatNode(StatNode): def generate_execution_code(self, code): code.mark_pos(self.pos) end_label = code.new_label() - last = len(self.if_clauses) + last = len(self.if_clauses) if self.else_clause: # If the 'else' clause is 'unlikely', then set the preceding 'if' clause to 'likely' to reflect that. self._set_branch_hint(self.if_clauses[-1], self.else_clause, inverse=True) else: - last -= 1 # avoid redundant goto at end of last if-clause - for i, if_clause in enumerate(self.if_clauses): + last -= 1 # avoid redundant goto at end of last if-clause + for i, if_clause in enumerate(self.if_clauses): self._set_branch_hint(if_clause, if_clause.body) - if_clause.generate_execution_code(code, end_label, is_last=i == last) + if_clause.generate_execution_code(code, end_label, is_last=i == last) if self.else_clause: - code.mark_pos(self.else_clause.pos) + code.mark_pos(self.else_clause.pos) code.putln("/*else*/ {") self.else_clause.generate_execution_code(code) code.putln("}") @@ -6328,13 +6328,13 @@ class IfClauseNode(Node): self.body.analyse_declarations(env) def analyse_expressions(self, env): - self.condition = self.condition.analyse_temp_boolean_expression(env) + self.condition = self.condition.analyse_temp_boolean_expression(env) self.body = self.body.analyse_expressions(env) return self - def generate_execution_code(self, code, end_label, is_last): + def generate_execution_code(self, code, end_label, is_last): self.condition.generate_evaluation_code(code) - code.mark_pos(self.pos) + code.mark_pos(self.pos) condition = self.condition.result() if self.branch_hint: condition = '%s(%s)' % (self.branch_hint, condition) @@ -6342,8 +6342,8 @@ class IfClauseNode(Node): self.condition.generate_disposal_code(code) self.condition.free_temps(code) self.body.generate_execution_code(code) - code.mark_pos(self.pos, trace=False) - if not (is_last or self.body.is_terminator): + code.mark_pos(self.pos, trace=False) + if not (is_last or self.body.is_terminator): code.put_goto(end_label) code.putln("}") @@ -6364,21 +6364,21 @@ class SwitchCaseNode(StatNode): child_attrs = ['conditions', 'body'] - def generate_condition_evaluation_code(self, code): + def generate_condition_evaluation_code(self, code): for cond in self.conditions: cond.generate_evaluation_code(code) - - def generate_execution_code(self, code): - num_conditions = len(self.conditions) - line_tracing_enabled = code.globalstate.directives['linetrace'] - for i, cond in enumerate(self.conditions, 1): + + def generate_execution_code(self, code): + num_conditions = len(self.conditions) + line_tracing_enabled = code.globalstate.directives['linetrace'] + for i, cond in enumerate(self.conditions, 1): code.putln("case %s:" % cond.result()) - code.mark_pos(cond.pos) # Tracing code must appear *after* the 'case' statement. - if line_tracing_enabled and i < num_conditions: - # Allow fall-through after the line tracing code. - code.putln('CYTHON_FALLTHROUGH;') + code.mark_pos(cond.pos) # Tracing code must appear *after* the 'case' statement. + if line_tracing_enabled and i < num_conditions: + # Allow fall-through after the line tracing code. + code.putln('CYTHON_FALLTHROUGH;') self.body.generate_execution_code(code) - code.mark_pos(self.pos, trace=False) + code.mark_pos(self.pos, trace=False) code.putln("break;") def generate_function_definitions(self, env, code): @@ -6391,7 +6391,7 @@ class SwitchCaseNode(StatNode): cond.annotate(code) self.body.annotate(code) - + class SwitchStatNode(StatNode): # Generated in the optimization of an if-elif-else node # @@ -6403,11 +6403,11 @@ class SwitchStatNode(StatNode): def generate_execution_code(self, code): self.test.generate_evaluation_code(code) - # Make sure all conditions are evaluated before going into the switch() statement. - # This is required in order to prevent any execution code from leaking into the space between the cases. - for case in self.cases: - case.generate_condition_evaluation_code(code) - code.mark_pos(self.pos) + # Make sure all conditions are evaluated before going into the switch() statement. + # This is required in order to prevent any execution code from leaking into the space between the cases. + for case in self.cases: + case.generate_condition_evaluation_code(code) + code.mark_pos(self.pos) code.putln("switch (%s) {" % self.test.result()) for case in self.cases: case.generate_execution_code(code) @@ -6438,7 +6438,7 @@ class SwitchStatNode(StatNode): if self.else_clause is not None: self.else_clause.annotate(code) - + class LoopNode(object): pass @@ -6466,7 +6466,7 @@ class WhileStatNode(LoopNode, StatNode): return self def generate_execution_code(self, code): - code.mark_pos(self.pos) + code.mark_pos(self.pos) old_loop_labels = code.new_loop_labels() code.putln( "while (1) {") @@ -6474,7 +6474,7 @@ class WhileStatNode(LoopNode, StatNode): self.condition.generate_evaluation_code(code) self.condition.generate_disposal_code(code) code.putln( - "if (!%s) break;" % self.condition.result()) + "if (!%s) break;" % self.condition.result()) self.condition.free_temps(code) self.body.generate_execution_code(code) code.put_label(code.continue_label) @@ -6519,15 +6519,15 @@ class DictIterationNextNode(Node): key_target, value_target, tuple_target, is_dict_flag): Node.__init__( self, dict_obj.pos, - dict_obj=dict_obj, - expected_size=expected_size, - pos_index_var=pos_index_var, - key_target=key_target, - value_target=value_target, - tuple_target=tuple_target, - is_dict_flag=is_dict_flag, - is_temp=True, - type=PyrexTypes.c_bint_type) + dict_obj=dict_obj, + expected_size=expected_size, + pos_index_var=pos_index_var, + key_target=key_target, + value_target=value_target, + tuple_target=tuple_target, + is_dict_flag=is_dict_flag, + is_temp=True, + type=PyrexTypes.c_bint_type) def analyse_expressions(self, env): from . import ExprNodes @@ -6594,7 +6594,7 @@ class DictIterationNextNode(Node): target.generate_assignment_code(result, code) var.release(code) - + class SetIterationNextNode(Node): # Helper node for calling _PySet_NextEntry() inside of a WhileStatNode # and checking the set size for changes. Created in Optimize.py. @@ -6657,46 +6657,46 @@ class SetIterationNextNode(Node): def ForStatNode(pos, **kw): if 'iterator' in kw: - if kw['iterator'].is_async: - return AsyncForStatNode(pos, **kw) - else: - return ForInStatNode(pos, **kw) + if kw['iterator'].is_async: + return AsyncForStatNode(pos, **kw) + else: + return ForInStatNode(pos, **kw) else: return ForFromStatNode(pos, **kw) - -class _ForInStatNode(LoopNode, StatNode): - # Base class of 'for-in' statements. + +class _ForInStatNode(LoopNode, StatNode): + # Base class of 'for-in' statements. # # target ExprNode - # iterator IteratorNode | AIterAwaitExprNode(AsyncIteratorNode) + # iterator IteratorNode | AIterAwaitExprNode(AsyncIteratorNode) # body StatNode # else_clause StatNode - # item NextNode | AwaitExprNode(AsyncNextNode) - # is_async boolean true for 'async for' statements + # item NextNode | AwaitExprNode(AsyncNextNode) + # is_async boolean true for 'async for' statements - child_attrs = ["target", "item", "iterator", "body", "else_clause"] + child_attrs = ["target", "item", "iterator", "body", "else_clause"] item = None - is_async = False + is_async = False + + def _create_item_node(self): + raise NotImplementedError("must be implemented by subclasses") - def _create_item_node(self): - raise NotImplementedError("must be implemented by subclasses") - def analyse_declarations(self, env): self.target.analyse_target_declaration(env) self.body.analyse_declarations(env) if self.else_clause: self.else_clause.analyse_declarations(env) - self._create_item_node() + self._create_item_node() def analyse_expressions(self, env): self.target = self.target.analyse_target_types(env) self.iterator = self.iterator.analyse_expressions(env) - self._create_item_node() # must rewrap self.item after analysis + self._create_item_node() # must rewrap self.item after analysis self.item = self.item.analyse_expressions(env) - if (not self.is_async and - (self.iterator.type.is_ptr or self.iterator.type.is_array) and - self.target.type.assignable_from(self.iterator.type)): + if (not self.is_async and + (self.iterator.type.is_ptr or self.iterator.type.is_array) and + self.target.type.assignable_from(self.iterator.type)): # C array slice optimization. pass else: @@ -6707,7 +6707,7 @@ class _ForInStatNode(LoopNode, StatNode): return self def generate_execution_code(self, code): - code.mark_pos(self.pos) + code.mark_pos(self.pos) old_loop_labels = code.new_loop_labels() self.iterator.generate_evaluation_code(code) code.putln("for (;;) {") @@ -6762,36 +6762,36 @@ class _ForInStatNode(LoopNode, StatNode): self.item.annotate(code) -class ForInStatNode(_ForInStatNode): - # 'for' statement - - is_async = False - - def _create_item_node(self): - from .ExprNodes import NextNode - self.item = NextNode(self.iterator) - - -class AsyncForStatNode(_ForInStatNode): - # 'async for' statement - # - # iterator AIterAwaitExprNode(AsyncIteratorNode) - # item AwaitIterNextExprNode(AsyncIteratorNode) - - is_async = True - +class ForInStatNode(_ForInStatNode): + # 'for' statement + + is_async = False + + def _create_item_node(self): + from .ExprNodes import NextNode + self.item = NextNode(self.iterator) + + +class AsyncForStatNode(_ForInStatNode): + # 'async for' statement + # + # iterator AIterAwaitExprNode(AsyncIteratorNode) + # item AwaitIterNextExprNode(AsyncIteratorNode) + + is_async = True + def __init__(self, pos, **kw): - assert 'item' not in kw - from . import ExprNodes - # AwaitExprNodes must appear before running MarkClosureVisitor + assert 'item' not in kw + from . import ExprNodes + # AwaitExprNodes must appear before running MarkClosureVisitor kw['item'] = ExprNodes.AwaitIterNextExprNode(kw['iterator'].pos, arg=None) - _ForInStatNode.__init__(self, pos, **kw) - - def _create_item_node(self): - from . import ExprNodes - self.item.arg = ExprNodes.AsyncNextNode(self.iterator) - - + _ForInStatNode.__init__(self, pos, **kw) + + def _create_item_node(self): + from . import ExprNodes + self.item.arg = ExprNodes.AsyncNextNode(self.iterator) + + class ForFromStatNode(LoopNode, StatNode): # for name from expr rel name rel expr # @@ -6837,8 +6837,8 @@ class ForFromStatNode(LoopNode, StatNode): self.bound2 = self.bound2.analyse_types(env) if self.step is not None: if isinstance(self.step, ExprNodes.UnaryMinusNode): - warning(self.step.pos, "Probable infinite loop in for-from-by statement. " - "Consider switching the directions of the relations.", 2) + warning(self.step.pos, "Probable infinite loop in for-from-by statement. " + "Consider switching the directions of the relations.", 2) self.step = self.step.analyse_types(env) self.set_up_loop(env) @@ -6879,8 +6879,8 @@ class ForFromStatNode(LoopNode, StatNode): if target_type.is_numeric or target_type.is_enum: self.is_py_target = False - if isinstance(self.target, ExprNodes.BufferIndexNode): - raise error(self.pos, "Buffer or memoryview slicing/indexing not allowed as for-loop target.") + if isinstance(self.target, ExprNodes.BufferIndexNode): + raise error(self.pos, "Buffer or memoryview slicing/indexing not allowed as for-loop target.") self.loopvar_node = self.target self.py_loopvar_node = None else: @@ -6890,7 +6890,7 @@ class ForFromStatNode(LoopNode, StatNode): self.py_loopvar_node = ExprNodes.CloneNode(c_loopvar_node).coerce_to_pyobject(env) def generate_execution_code(self, code): - code.mark_pos(self.pos) + code.mark_pos(self.pos) old_loop_labels = code.new_loop_labels() from_range = self.from_range self.bound1.generate_evaluation_code(code) @@ -6916,19 +6916,19 @@ class ForFromStatNode(LoopNode, StatNode): else: loopvar_name = self.loopvar_node.result() if loopvar_type.is_int and not loopvar_type.signed and self.relation2[0] == '>': - # Handle the case where the endpoint of an unsigned int iteration - # is within step of 0. - code.putln("for (%s = %s%s + %s; %s %s %s + %s; ) { %s%s;" % ( - loopvar_name, - self.bound1.result(), offset, step, - loopvar_name, self.relation2, self.bound2.result(), step, - loopvar_name, incop)) - else: - code.putln("for (%s = %s%s; %s %s %s; %s%s) {" % ( - loopvar_name, - self.bound1.result(), offset, - loopvar_name, self.relation2, self.bound2.result(), - loopvar_name, incop)) + # Handle the case where the endpoint of an unsigned int iteration + # is within step of 0. + code.putln("for (%s = %s%s + %s; %s %s %s + %s; ) { %s%s;" % ( + loopvar_name, + self.bound1.result(), offset, step, + loopvar_name, self.relation2, self.bound2.result(), step, + loopvar_name, incop)) + else: + code.putln("for (%s = %s%s; %s %s %s; %s%s) {" % ( + loopvar_name, + self.bound1.result(), offset, + loopvar_name, self.relation2, self.bound2.result(), + loopvar_name, incop)) coerced_loopvar_node = self.py_loopvar_node if coerced_loopvar_node is None and from_range: @@ -6952,15 +6952,15 @@ class ForFromStatNode(LoopNode, StatNode): if self.target.entry.scope.is_module_scope: code.globalstate.use_utility_code( UtilityCode.load_cached("GetModuleGlobalName", "ObjectHandling.c")) - lookup_func = '__Pyx_GetModuleGlobalName(%s, %s); %s' + lookup_func = '__Pyx_GetModuleGlobalName(%s, %s); %s' else: code.globalstate.use_utility_code( UtilityCode.load_cached("GetNameInClass", "ObjectHandling.c")) - lookup_func = '__Pyx_GetNameInClass(%s, {}, %s); %s'.format( + lookup_func = '__Pyx_GetNameInClass(%s, {}, %s); %s'.format( self.target.entry.scope.namespace_cname) - code.putln(lookup_func % ( + code.putln(lookup_func % ( target_node.result(), - interned_cname, + interned_cname, code.error_goto_if_null(target_node.result(), self.target.pos))) code.put_gotref(target_node.result()) else: @@ -7007,7 +7007,7 @@ class ForFromStatNode(LoopNode, StatNode): '<=': ("", "++"), '<' : ("+1", "++"), '>=': ("", "--"), - '>' : ("-1", "--"), + '>' : ("-1", "--"), } def generate_function_definitions(self, env, code): @@ -7086,7 +7086,7 @@ class WithStatNode(StatNode): self.body.generate_function_definitions(env, code) def generate_execution_code(self, code): - code.mark_pos(self.pos) + code.mark_pos(self.pos) code.putln("/*with:*/ {") self.manager.generate_evaluation_code(code) self.exit_var = code.funcstate.allocate_temp(py_object_type, manage_ref=False) @@ -7095,7 +7095,7 @@ class WithStatNode(StatNode): code.putln("%s = __Pyx_PyObject_LookupSpecial(%s, %s); %s" % ( self.exit_var, self.manager.py_result(), - code.intern_identifier(EncodedString('__aexit__' if self.is_async else '__exit__')), + code.intern_identifier(EncodedString('__aexit__' if self.is_async else '__exit__')), code.error_goto_if_null(self.exit_var, self.pos), )) code.put_gotref(self.exit_var) @@ -7202,9 +7202,9 @@ class TryExceptStatNode(StatNode): gil_message = "Try-except statement" def generate_execution_code(self, code): - code.mark_pos(self.pos) # before changing the error label, in case of tracing errors - code.putln("{") - + code.mark_pos(self.pos) # before changing the error label, in case of tracing errors + code.putln("{") + old_return_label = code.return_label old_break_label = code.break_label old_continue_label = code.continue_label @@ -7219,7 +7219,7 @@ class TryExceptStatNode(StatNode): try_end_label = code.new_label('try_end') exc_save_vars = [code.funcstate.allocate_temp(py_object_type, False) - for _ in range(3)] + for _ in range(3)] save_exc = code.insertion_point() code.putln( "/*try:*/ {") @@ -7227,7 +7227,7 @@ class TryExceptStatNode(StatNode): code.break_label = try_break_label code.continue_label = try_continue_label self.body.generate_execution_code(code) - code.mark_pos(self.pos, trace=False) + code.mark_pos(self.pos, trace=False) code.putln( "}") temps_to_clean_up = code.funcstate.all_free_managed_temps() @@ -7239,8 +7239,8 @@ class TryExceptStatNode(StatNode): if not self.in_generator: save_exc.putln("__Pyx_PyThreadState_declare") save_exc.putln("__Pyx_PyThreadState_assign") - save_exc.putln("__Pyx_ExceptionSave(%s);" % ( - ', '.join(['&%s' % var for var in exc_save_vars]))) + save_exc.putln("__Pyx_ExceptionSave(%s);" % ( + ', '.join(['&%s' % var for var in exc_save_vars]))) for var in exc_save_vars: save_exc.put_xgotref(var) @@ -7262,7 +7262,7 @@ class TryExceptStatNode(StatNode): code.return_label = except_return_label normal_case_terminates = self.body.is_terminator if self.else_clause: - code.mark_pos(self.else_clause.pos) + code.mark_pos(self.else_clause.pos) code.putln( "/*else:*/ {") self.else_clause.generate_execution_code(code) @@ -7299,17 +7299,17 @@ class TryExceptStatNode(StatNode): if not normal_case_terminates and not code.label_used(try_end_label): code.put_goto(try_end_label) code.put_label(exit_label) - code.mark_pos(self.pos, trace=False) - if can_raise: - restore_saved_exception() + code.mark_pos(self.pos, trace=False) + if can_raise: + restore_saved_exception() code.put_goto(old_label) if code.label_used(except_end_label): if not normal_case_terminates and not code.label_used(try_end_label): code.put_goto(try_end_label) code.put_label(except_end_label) - if can_raise: - restore_saved_exception() + if can_raise: + restore_saved_exception() if code.label_used(try_end_label): code.put_label(try_end_label) code.putln("}") @@ -7431,22 +7431,22 @@ class ExceptClauseNode(Node): and self.target is None): # most simple case: no exception variable, empty body (pass) # => reset the exception state, done - code.globalstate.use_utility_code(UtilityCode.load_cached("PyErrFetchRestore", "Exceptions.c")) - code.putln("__Pyx_ErrRestore(0,0,0);") + code.globalstate.use_utility_code(UtilityCode.load_cached("PyErrFetchRestore", "Exceptions.c")) + code.putln("__Pyx_ErrRestore(0,0,0);") code.put_goto(end_label) code.putln("}") return exc_vars = [code.funcstate.allocate_temp(py_object_type, manage_ref=True) - for _ in range(3)] + for _ in range(3)] code.put_add_traceback(self.function_name) # We always have to fetch the exception value even if # there is no target, because this also normalises the # exception and stores it in the thread state. code.globalstate.use_utility_code(get_exception_utility_code) exc_args = "&%s, &%s, &%s" % tuple(exc_vars) - code.putln("if (__Pyx_GetException(%s) < 0) %s" % ( - exc_args, code.error_goto(self.pos))) + code.putln("if (__Pyx_GetException(%s) < 0) %s" % ( + exc_args, code.error_goto(self.pos))) for var in exc_vars: code.put_gotref(var) if self.target: @@ -7468,9 +7468,9 @@ class ExceptClauseNode(Node): if not self.body.is_terminator: for var in exc_vars: - # FIXME: XDECREF() is needed to allow re-raising (which clears the exc_vars), - # but I don't think it's the right solution. - code.put_xdecref_clear(var, py_object_type) + # FIXME: XDECREF() is needed to allow re-raising (which clears the exc_vars), + # but I don't think it's the right solution. + code.put_xdecref_clear(var, py_object_type) code.put_goto(end_label) for new_label, old_label in [(code.break_label, old_break_label), @@ -7508,42 +7508,42 @@ class TryFinallyStatNode(StatNode): # # body StatNode # finally_clause StatNode - # finally_except_clause deep-copy of finally_clause for exception case + # finally_except_clause deep-copy of finally_clause for exception case # in_generator inside of generator => must store away current exception also in return case # - # Each of the continue, break, return and error gotos runs - # into its own deep-copy of the finally block code. + # Each of the continue, break, return and error gotos runs + # into its own deep-copy of the finally block code. # In addition, if we're doing an error, we save the # exception on entry to the finally block and restore # it on exit. - child_attrs = ["body", "finally_clause", "finally_except_clause"] + child_attrs = ["body", "finally_clause", "finally_except_clause"] preserve_exception = 1 # handle exception case, in addition to return/break/continue handle_error_case = True func_return_type = None - finally_except_clause = None + finally_except_clause = None is_try_finally_in_nogil = False in_generator = False - @staticmethod + @staticmethod def create_analysed(pos, env, body, finally_clause): node = TryFinallyStatNode(pos, body=body, finally_clause=finally_clause) return node def analyse_declarations(self, env): self.body.analyse_declarations(env) - self.finally_except_clause = copy.deepcopy(self.finally_clause) - self.finally_except_clause.analyse_declarations(env) + self.finally_except_clause = copy.deepcopy(self.finally_clause) + self.finally_except_clause.analyse_declarations(env) self.finally_clause.analyse_declarations(env) def analyse_expressions(self, env): self.body = self.body.analyse_expressions(env) self.finally_clause = self.finally_clause.analyse_expressions(env) - self.finally_except_clause = self.finally_except_clause.analyse_expressions(env) + self.finally_except_clause = self.finally_except_clause.analyse_expressions(env) if env.return_type and not env.return_type.is_void: self.func_return_type = env.return_type return self @@ -7552,9 +7552,9 @@ class TryFinallyStatNode(StatNode): gil_message = "Try-finally statement" def generate_execution_code(self, code): - code.mark_pos(self.pos) # before changing the error label, in case of tracing errors - code.putln("/*try:*/ {") - + code.mark_pos(self.pos) # before changing the error label, in case of tracing errors + code.putln("/*try:*/ {") + old_error_label = code.error_label old_labels = code.all_new_labels() new_labels = code.get_all_labels() @@ -7563,21 +7563,21 @@ class TryFinallyStatNode(StatNode): code.error_label = old_error_label catch_label = code.new_label() - was_in_try_finally = code.funcstate.in_try_finally - code.funcstate.in_try_finally = 1 + was_in_try_finally = code.funcstate.in_try_finally + code.funcstate.in_try_finally = 1 self.body.generate_execution_code(code) - code.funcstate.in_try_finally = was_in_try_finally + code.funcstate.in_try_finally = was_in_try_finally code.putln("}") temps_to_clean_up = code.funcstate.all_free_managed_temps() code.mark_pos(self.finally_clause.pos) code.putln("/*finally:*/ {") - # Reset labels only after writing out a potential line trace call for correct nogil error handling. - code.set_all_labels(old_labels) - + # Reset labels only after writing out a potential line trace call for correct nogil error handling. + code.set_all_labels(old_labels) + def fresh_finally_clause(_next=[self.finally_clause]): # generate the original subtree once and always keep a fresh copy node = _next[0] @@ -7624,7 +7624,7 @@ class TryFinallyStatNode(StatNode): code.putln('{') old_exc_vars = code.funcstate.exc_vars code.funcstate.exc_vars = exc_vars[:3] - self.finally_except_clause.generate_execution_code(code) + self.finally_except_clause.generate_execution_code(code) code.funcstate.exc_vars = old_exc_vars code.putln('}') @@ -7712,7 +7712,7 @@ class TryFinallyStatNode(StatNode): if self.is_try_finally_in_nogil: code.put_ensure_gil(declare_gilstate=False) - code.putln("__Pyx_PyThreadState_assign") + code.putln("__Pyx_PyThreadState_assign") code.putln(' '.join(["%s = 0;" % var for var in exc_vars])) for temp_name, type in temps_to_clean_up: @@ -7770,7 +7770,7 @@ class TryFinallyStatNode(StatNode): code.globalstate.use_utility_code(reset_exception_utility_code) if self.is_try_finally_in_nogil: code.put_ensure_gil(declare_gilstate=False) - + # not using preprocessor here to avoid warnings about # unused utility functions and/or temps code.putln("if (PY_MAJOR_VERSION >= 3) {") @@ -7808,8 +7808,8 @@ class GILStatNode(NogilTryFinallyStatNode): def __init__(self, pos, state, body): self.state = state self.create_state_temp_if_needed(pos, state, body) - TryFinallyStatNode.__init__( - self, pos, + TryFinallyStatNode.__init__( + self, pos, body=body, finally_clause=GILExitNode( pos, state=state, state_temp=self.state_temp)) @@ -7853,20 +7853,20 @@ class GILStatNode(NogilTryFinallyStatNode): else: variable = None - old_gil_config = code.funcstate.gil_owned + old_gil_config = code.funcstate.gil_owned if self.state == 'gil': code.put_ensure_gil(variable=variable) - code.funcstate.gil_owned = True + code.funcstate.gil_owned = True else: code.put_release_gil(variable=variable) - code.funcstate.gil_owned = False + code.funcstate.gil_owned = False TryFinallyStatNode.generate_execution_code(self, code) if self.state_temp: self.state_temp.release(code) - code.funcstate.gil_owned = old_gil_config + code.funcstate.gil_owned = old_gil_config code.end_block() @@ -7903,44 +7903,44 @@ class EnsureGILNode(GILExitNode): def generate_execution_code(self, code): code.put_ensure_gil(declare_gilstate=False) - -def cython_view_utility_code(): - from . import MemoryView - return MemoryView.view_utility_code - - + +def cython_view_utility_code(): + from . import MemoryView + return MemoryView.view_utility_code + + utility_code_for_cimports = { # utility code (or inlining c) in a pxd (or pyx) file. # TODO: Consider a generic user-level mechanism for importing - 'cpython.array' : lambda : UtilityCode.load_cached("ArrayAPI", "arrayarray.h"), - 'cpython.array.array' : lambda : UtilityCode.load_cached("ArrayAPI", "arrayarray.h"), - 'cython.view' : cython_view_utility_code, + 'cpython.array' : lambda : UtilityCode.load_cached("ArrayAPI", "arrayarray.h"), + 'cpython.array.array' : lambda : UtilityCode.load_cached("ArrayAPI", "arrayarray.h"), + 'cython.view' : cython_view_utility_code, +} + +utility_code_for_imports = { + # utility code used when special modules are imported. + # TODO: Consider a generic user-level mechanism for importing + 'asyncio': ("__Pyx_patch_asyncio", "PatchAsyncIO", "Coroutine.c"), + 'inspect': ("__Pyx_patch_inspect", "PatchInspect", "Coroutine.c"), } -utility_code_for_imports = { - # utility code used when special modules are imported. - # TODO: Consider a generic user-level mechanism for importing - 'asyncio': ("__Pyx_patch_asyncio", "PatchAsyncIO", "Coroutine.c"), - 'inspect': ("__Pyx_patch_inspect", "PatchInspect", "Coroutine.c"), -} - - + class CImportStatNode(StatNode): # cimport statement # # module_name string Qualified name of module being imported # as_name string or None Name specified in "as" clause, if any - # is_absolute bool True for absolute imports, False otherwise + # is_absolute bool True for absolute imports, False otherwise child_attrs = [] - is_absolute = False + is_absolute = False def analyse_declarations(self, env): if not env.is_module_scope: error(self.pos, "cimport only allowed at module level") return - module_scope = env.find_module( - self.module_name, self.pos, relative_level=0 if self.is_absolute else -1) + module_scope = env.find_module( + self.module_name, self.pos, relative_level=0 if self.is_absolute else -1) if "." in self.module_name: names = [EncodedString(name) for name in self.module_name.split(".")] top_name = names[0] @@ -7959,7 +7959,7 @@ class CImportStatNode(StatNode): name = self.as_name or self.module_name env.declare_module(name, module_scope, self.pos) if self.module_name in utility_code_for_cimports: - env.use_utility_code(utility_code_for_cimports[self.module_name]()) + env.use_utility_code(utility_code_for_cimports[self.module_name]()) def analyse_expressions(self, env): return self @@ -7986,13 +7986,13 @@ class FromCImportStatNode(StatNode): return if self.relative_level and self.relative_level > env.qualified_name.count('.'): error(self.pos, "relative cimport beyond main package is not allowed") - return + return module_scope = env.find_module(self.module_name, self.pos, relative_level=self.relative_level) module_name = module_scope.qualified_name env.add_imported_module(module_scope) for pos, name, as_name, kind in self.imported_names: if name == "*": - for local_name, entry in list(module_scope.entries.items()): + for local_name, entry in list(module_scope.entries.items()): env.add_imported_entry(local_name, entry, pos) else: entry = module_scope.lookup(name) @@ -8007,8 +8007,8 @@ class FromCImportStatNode(StatNode): elif kind == 'class': entry = module_scope.declare_c_class(name, pos=pos, module_name=module_name) else: - submodule_scope = env.context.find_module( - name, relative_to=module_scope, pos=self.pos, absolute_fallback=False) + submodule_scope = env.context.find_module( + name, relative_to=module_scope, pos=self.pos, absolute_fallback=False) if submodule_scope.parent_module is module_scope: env.declare_module(as_name or name, submodule_scope, self.pos) else: @@ -8018,13 +8018,13 @@ class FromCImportStatNode(StatNode): local_name = as_name or name env.add_imported_entry(local_name, entry, pos) - if module_name.startswith('cpython') or module_name.startswith('cython'): # enough for now + if module_name.startswith('cpython') or module_name.startswith('cython'): # enough for now if module_name in utility_code_for_cimports: - env.use_utility_code(utility_code_for_cimports[module_name]()) + env.use_utility_code(utility_code_for_cimports[module_name]()) for _, name, _, _ in self.imported_names: fqname = '%s.%s' % (module_name, name) if fqname in utility_code_for_cimports: - env.use_utility_code(utility_code_for_cimports[fqname]()) + env.use_utility_code(utility_code_for_cimports[fqname]()) def declaration_matches(self, entry, kind): if not entry.is_type: @@ -8106,7 +8106,7 @@ class FromImportStatNode(StatNode): return self def generate_execution_code(self, code): - code.mark_pos(self.pos) + code.mark_pos(self.pos) self.module.generate_evaluation_code(code) if self.import_star: code.putln( @@ -8253,13 +8253,13 @@ class ParallelStatNode(StatNode, ParallelNode): try: self.kwargs = self.kwargs.compile_time_value(env) - except Exception as e: + except Exception as e: error(self.kwargs.pos, "Only compile-time values may be " "supplied as keyword arguments") else: self.kwargs = {} - for kw, val in self.kwargs.items(): + for kw, val in self.kwargs.items(): if kw not in self.valid_keyword_arguments: error(self.pos, "Invalid keyword argument: %s" % kw) else: @@ -8276,14 +8276,14 @@ class ParallelStatNode(StatNode, ParallelNode): self.analyse_sharing_attributes(env) if self.num_threads is not None: - if self.parent and self.parent.num_threads is not None and not self.parent.is_prange: - error(self.pos, "num_threads already declared in outer section") + if self.parent and self.parent.num_threads is not None and not self.parent.is_prange: + error(self.pos, "num_threads already declared in outer section") elif self.parent and not self.parent.is_prange: - error(self.pos, "num_threads must be declared in the parent parallel section") + error(self.pos, "num_threads must be declared in the parent parallel section") elif (self.num_threads.type.is_int and - self.num_threads.is_literal and - self.num_threads.compile_time_value(env) <= 0): - error(self.pos, "argument to num_threads must be greater than 0") + self.num_threads.is_literal and + self.num_threads.compile_time_value(env) <= 0): + error(self.pos, "argument to num_threads must be greater than 0") if not self.num_threads.is_simple() or self.num_threads.type.is_pyobject: self.num_threads = self.num_threads.coerce_to( @@ -8296,14 +8296,14 @@ class ParallelStatNode(StatNode, ParallelNode): This should be called in a post-order fashion during the analyse_expressions phase """ - for entry, (pos, op) in self.assignments.items(): + for entry, (pos, op) in self.assignments.items(): if self.is_prange and not self.is_parallel: # closely nested prange in a with parallel block, disallow # assigning to privates in the with parallel block (we # consider it too implicit and magicky for users) if entry in self.parent.assignments: - error(pos, "Cannot assign to private of outer parallel block") + error(pos, "Cannot assign to private of outer parallel block") continue if not self.is_prange and op: @@ -8412,7 +8412,7 @@ class ParallelStatNode(StatNode, ParallelNode): def initialize_privates_to_nan(self, code, exclude=None): first = True - for entry, (op, lastprivate) in sorted(self.privates.items()): + for entry, (op, lastprivate) in sorted(self.privates.items()): if not op and (not exclude or entry != exclude): invalid_value = entry.type.invalid_value() @@ -8441,7 +8441,7 @@ class ParallelStatNode(StatNode, ParallelNode): Write self.num_threads if set as the num_threads OpenMP directive """ if self.num_threads is not None: - code.put(" num_threads(%s)" % self.evaluate_before_block(code, self.num_threads)) + code.put(" num_threads(%s)" % self.evaluate_before_block(code, self.num_threads)) def declare_closure_privates(self, code): @@ -8453,7 +8453,7 @@ class ParallelStatNode(StatNode, ParallelNode): """ self.modified_entries = [] - for entry in sorted(self.assignments): + for entry in sorted(self.assignments): if entry.from_closure or entry.in_closure: self._allocate_closure_temp(code, entry) @@ -8473,13 +8473,13 @@ class ParallelStatNode(StatNode, ParallelNode): Make any used temporaries private. Before the relevant code block code.start_collecting_temps() should have been called. """ - c = self.privatization_insertion_point - self.privatization_insertion_point = None - + c = self.privatization_insertion_point + self.privatization_insertion_point = None + if self.is_parallel: self.temps = temps = code.funcstate.stop_collecting_temps() privates, firstprivates = [], [] - for temp, type in sorted(temps): + for temp, type in sorted(temps): if type.is_pyobject or type.is_memoryviewslice: firstprivates.append(temp) else: @@ -8502,7 +8502,7 @@ class ParallelStatNode(StatNode, ParallelNode): # Now clean up any memoryview slice and object temporaries if self.is_parallel and not self.is_nested_prange: code.putln("/* Clean up any temporaries */") - for temp, type in sorted(self.temps): + for temp, type in sorted(self.temps): if type.is_memoryviewslice: code.put_xdecref_memoryviewslice(temp, have_gil=False) elif type.is_pyobject: @@ -8567,9 +8567,9 @@ class ParallelStatNode(StatNode, ParallelNode): If compiled without OpenMP support (at the C level), then we still have to acquire the GIL to decref any object temporaries. """ - begin_code = self.begin_of_parallel_block - self.begin_of_parallel_block = None - + begin_code = self.begin_of_parallel_block + self.begin_of_parallel_block = None + if self.error_label_used: end_code = code @@ -8666,7 +8666,7 @@ class ParallelStatNode(StatNode, ParallelNode): that the breaking thread has well-defined values of the lastprivate variables, so we keep those values. """ - section_name = "__pyx_parallel_lastprivates%d" % self.critical_section_counter + section_name = "__pyx_parallel_lastprivates%d" % self.critical_section_counter code.putln_openmp("#pragma omp critical(%s)" % section_name) ParallelStatNode.critical_section_counter += 1 @@ -8675,11 +8675,11 @@ class ParallelStatNode(StatNode, ParallelNode): c = self.begin_of_parallel_control_block_point temp_count = 0 - for entry, (op, lastprivate) in sorted(self.privates.items()): + for entry, (op, lastprivate) in sorted(self.privates.items()): if not lastprivate or entry.type.is_pyobject: continue - type_decl = entry.type.empty_declaration_code() + type_decl = entry.type.empty_declaration_code() temp_cname = "__pyx_parallel_temp%d" % temp_count private_cname = entry.cname @@ -8734,7 +8734,7 @@ class ParallelStatNode(StatNode, ParallelNode): code.putln( "if (!%s) {" % Naming.parallel_exc_type) - code.putln("__Pyx_ErrFetchWithState(&%s, &%s, &%s);" % self.parallel_exc) + code.putln("__Pyx_ErrFetchWithState(&%s, &%s, &%s);" % self.parallel_exc) pos_info = chain(*zip(self.parallel_pos_info, self.pos_info)) code.funcstate.uses_error_indicator = True code.putln("%s = %s; %s = %s; %s = %s;" % tuple(pos_info)) @@ -8752,7 +8752,7 @@ class ParallelStatNode(StatNode, ParallelNode): code.put_ensure_gil(declare_gilstate=True) code.put_giveref(Naming.parallel_exc_type) - code.putln("__Pyx_ErrRestoreWithState(%s, %s, %s);" % self.parallel_exc) + code.putln("__Pyx_ErrRestoreWithState(%s, %s, %s);" % self.parallel_exc) pos_info = chain(*zip(self.pos_info, self.parallel_pos_info)) code.putln("%s = %s; %s = %s; %s = %s;" % tuple(pos_info)) @@ -8767,8 +8767,8 @@ class ParallelStatNode(StatNode, ParallelNode): code.set_all_labels(self.old_loop_labels + (self.old_return_label, self.old_error_label)) - def end_parallel_control_flow_block( - self, code, break_=False, continue_=False, return_=False): + def end_parallel_control_flow_block( + self, code, break_=False, continue_=False, return_=False): """ This ends the parallel control flow block and based on how the parallel section was exited, takes the corresponding action. The break_ and @@ -8783,8 +8783,8 @@ class ParallelStatNode(StatNode, ParallelNode): the for loop. """ c = self.begin_of_parallel_control_block_point - self.begin_of_parallel_control_block_point = None - self.begin_of_parallel_control_block_point_after_decls = None + self.begin_of_parallel_control_block_point = None + self.begin_of_parallel_control_block_point_after_decls = None if self.num_threads is not None: # FIXME: is it the right place? should not normally produce code. @@ -8793,8 +8793,8 @@ class ParallelStatNode(StatNode, ParallelNode): # Firstly, always prefer errors over returning, continue or break if self.error_label_used: - c.putln("const char *%s = NULL; int %s = 0, %s = 0;" % self.parallel_pos_info) - c.putln("PyObject *%s = NULL, *%s = NULL, *%s = NULL;" % self.parallel_exc) + c.putln("const char *%s = NULL; int %s = 0, %s = 0;" % self.parallel_pos_info) + c.putln("PyObject *%s = NULL, *%s = NULL, *%s = NULL;" % self.parallel_exc) code.putln( "if (%s) {" % Naming.parallel_exc_type) @@ -8829,9 +8829,9 @@ class ParallelStatNode(StatNode, ParallelNode): code.put(" case 2: ") code.put_goto(code.break_label) - if return_: - code.put(" case 3: ") - code.put_goto(code.return_label) + if return_: + code.put(" case 3: ") + code.put_goto(code.return_label) if self.error_label_used: code.globalstate.use_utility_code(restore_exception_utility_code) @@ -8888,8 +8888,8 @@ class ParallelWithBlockNode(ParallelStatNode): if self.privates: privates = [e.cname for e in self.privates - if not e.type.is_pyobject] - code.put('private(%s)' % ', '.join(sorted(privates))) + if not e.type.is_pyobject] + code.put('private(%s)' % ', '.join(sorted(privates))) self.privatization_insertion_point = code.insertion_point() self.put_num_threads(code) @@ -8897,7 +8897,7 @@ class ParallelWithBlockNode(ParallelStatNode): code.putln("#endif /* _OPENMP */") - code.begin_block() # parallel block + code.begin_block() # parallel block self.begin_parallel_block(code) self.initialize_privates_to_nan(code) code.funcstate.start_collecting_temps() @@ -8905,16 +8905,16 @@ class ParallelWithBlockNode(ParallelStatNode): self.trap_parallel_exit(code) self.privatize_temps(code) self.end_parallel_block(code) - code.end_block() # end parallel block + code.end_block() # end parallel block continue_ = code.label_used(code.continue_label) break_ = code.label_used(code.break_label) - return_ = code.label_used(code.return_label) + return_ = code.label_used(code.return_label) self.restore_labels(code) self.end_parallel_control_flow_block(code, break_=break_, - continue_=continue_, - return_=return_) + continue_=continue_, + return_=return_) self.release_closure_privates(code) @@ -8965,8 +8965,8 @@ class ParallelRangeNode(ParallelStatNode): if hasattr(self.schedule, 'decode'): self.schedule = self.schedule.decode('ascii') - if self.schedule not in (None, 'static', 'dynamic', 'guided', 'runtime'): - error(self.pos, "Invalid schedule argument to prange: %s" % (self.schedule,)) + if self.schedule not in (None, 'static', 'dynamic', 'guided', 'runtime'): + error(self.pos, "Invalid schedule argument to prange: %s" % (self.schedule,)) def analyse_expressions(self, env): was_nogil = env.nogil @@ -9009,7 +9009,7 @@ class ParallelRangeNode(ParallelStatNode): # As we range from 0 to nsteps, computing the index along the # way, we need a fitting type for 'i' and 'nsteps' self.index_type = PyrexTypes.widest_numeric_type( - self.index_type, node.type) + self.index_type, node.type) if self.else_clause is not None: self.else_clause = self.else_clause.analyse_expressions(env) @@ -9110,7 +9110,7 @@ class ParallelRangeNode(ParallelStatNode): # the start, stop , step, temps and target cnames fmt_dict = { 'target': target_index_cname, - 'target_type': self.target.type.empty_declaration_code() + 'target_type': self.target.type.empty_declaration_code() } # Setup start, stop and step, allocating temps if needed @@ -9137,7 +9137,7 @@ class ParallelRangeNode(ParallelStatNode): self.setup_parallel_control_flow_block(code) # parallel control flow block # Note: nsteps is private in an outer scope if present - code.putln("%(nsteps)s = (%(stop)s - %(start)s + %(step)s - %(step)s/abs(%(step)s)) / %(step)s;" % fmt_dict) + code.putln("%(nsteps)s = (%(stop)s - %(start)s + %(step)s - %(step)s/abs(%(step)s)) / %(step)s;" % fmt_dict) # The target iteration variable might not be initialized, do it only if # we are executing at least 1 iteration, otherwise we should leave the @@ -9204,7 +9204,7 @@ class ParallelRangeNode(ParallelStatNode): code.putln("#ifdef _OPENMP") code.put("#pragma omp for") - for entry, (op, lastprivate) in sorted(self.privates.items()): + for entry, (op, lastprivate) in sorted(self.privates.items()): # Don't declare the index variable as a reduction if op and op in "+*-&^|" and entry != self.target.entry: if entry.type.is_pyobject: @@ -9230,7 +9230,7 @@ class ParallelRangeNode(ParallelStatNode): if self.schedule: if self.chunksize: - chunksize = ", %s" % self.evaluate_before_block(code, self.chunksize) + chunksize = ", %s" % self.evaluate_before_block(code, self.chunksize) else: chunksize = "" @@ -9242,7 +9242,7 @@ class ParallelRangeNode(ParallelStatNode): code.putln("#endif /* _OPENMP */") code.put("for (%(i)s = 0; %(i)s < %(nsteps)s; %(i)s++)" % fmt_dict) - code.begin_block() # for loop block + code.begin_block() # for loop block guard_around_body_codepoint = code.insertion_point() @@ -9250,7 +9250,7 @@ class ParallelRangeNode(ParallelStatNode): # at least it doesn't spoil indentation code.begin_block() - code.putln("%(target)s = (%(target_type)s)(%(start)s + %(step)s * %(i)s);" % fmt_dict) + code.putln("%(target)s = (%(target_type)s)(%(start)s + %(step)s * %(i)s);" % fmt_dict) self.initialize_privates_to_nan(code, exclude=self.target.entry) if self.is_parallel and not self.is_nested_prange: @@ -9268,13 +9268,13 @@ class ParallelRangeNode(ParallelStatNode): # exceptions might be used guard_around_body_codepoint.putln("if (%s < 2)" % Naming.parallel_why) - code.end_block() # end guard around loop body - code.end_block() # end for loop block + code.end_block() # end guard around loop body + code.end_block() # end for loop block if self.is_parallel: # Release the GIL and deallocate the thread state self.end_parallel_block(code) - code.end_block() # pragma omp parallel end block + code.end_block() # pragma omp parallel end block class CnameDecoratorNode(StatNode): @@ -9301,7 +9301,7 @@ class CnameDecoratorNode(StatNode): node = node.body.stats[0] self.is_function = isinstance(node, FuncDefNode) - is_struct_or_enum = isinstance(node, (CStructOrUnionDefNode, CEnumDefNode)) + is_struct_or_enum = isinstance(node, (CStructOrUnionDefNode, CEnumDefNode)) e = node.entry if self.is_function: @@ -9321,11 +9321,11 @@ class CnameDecoratorNode(StatNode): e.type.typeptr_cname = self.cname + '_type' e.type.scope.namespace_cname = e.type.typeptr_cname - e.as_variable.cname = e.type.typeptr_cname + e.as_variable.cname = e.type.typeptr_cname scope.scope_prefix = self.cname + "_" - for name, entry in scope.entries.items(): + for name, entry in scope.entries.items(): if entry.func_cname: entry.func_cname = self.mangle(entry.cname) if entry.pyfunc_cname: @@ -9349,7 +9349,7 @@ class CnameDecoratorNode(StatNode): if isinstance(self.node, DefNode): self.node.generate_function_header( - h_code, with_pymethdef=False, proto_only=True) + h_code, with_pymethdef=False, proto_only=True) else: from . import ModuleNode entry = self.node.entry @@ -9357,10 +9357,10 @@ class CnameDecoratorNode(StatNode): entry.cname = entry.func_cname ModuleNode.generate_cfunction_declaration( - entry, - env.global_scope(), - h_code, - definition=True) + entry, + env.global_scope(), + h_code, + definition=True) entry.cname = cname @@ -9417,16 +9417,16 @@ traceback_utility_code = UtilityCode.load_cached("AddTraceback", "Exceptions.c") #------------------------------------------------------------------------------------ -get_exception_tuple_utility_code = UtilityCode( - proto=""" -static PyObject *__Pyx_GetExceptionTuple(PyThreadState *__pyx_tstate); /*proto*/ +get_exception_tuple_utility_code = UtilityCode( + proto=""" +static PyObject *__Pyx_GetExceptionTuple(PyThreadState *__pyx_tstate); /*proto*/ """, - # I doubt that calling __Pyx_GetException() here is correct as it moves - # the exception from tstate->curexc_* to tstate->exc_*, which prevents - # exception handlers later on from receiving it. - # NOTE: "__pyx_tstate" may be used by __Pyx_GetException() macro - impl = """ -static PyObject *__Pyx_GetExceptionTuple(CYTHON_UNUSED PyThreadState *__pyx_tstate) { + # I doubt that calling __Pyx_GetException() here is correct as it moves + # the exception from tstate->curexc_* to tstate->exc_*, which prevents + # exception handlers later on from receiving it. + # NOTE: "__pyx_tstate" may be used by __Pyx_GetException() macro + impl = """ +static PyObject *__Pyx_GetExceptionTuple(CYTHON_UNUSED PyThreadState *__pyx_tstate) { PyObject *type = NULL, *value = NULL, *tb = NULL; if (__Pyx_GetException(&type, &value, &tb) == 0) { PyObject* exc_info = PyTuple_New(3); @@ -9443,4 +9443,4 @@ static PyObject *__Pyx_GetExceptionTuple(CYTHON_UNUSED PyThreadState *__pyx_tsta return NULL; } """, - requires=[get_exception_utility_code]) + requires=[get_exception_utility_code]) diff --git a/contrib/tools/cython/Cython/Compiler/Optimize.py b/contrib/tools/cython/Cython/Compiler/Optimize.py index da4556a9f6..3cb77efe2c 100644 --- a/contrib/tools/cython/Cython/Compiler/Optimize.py +++ b/contrib/tools/cython/Cython/Compiler/Optimize.py @@ -1,25 +1,25 @@ from __future__ import absolute_import import re -import sys -import copy -import codecs -import itertools - +import sys +import copy +import codecs +import itertools + from . import TypeSlots from .ExprNodes import not_a_constant import cython cython.declare(UtilityCode=object, EncodedString=object, bytes_literal=object, encoded_string=object, Nodes=object, ExprNodes=object, PyrexTypes=object, Builtin=object, - UtilNodes=object, _py_int_types=object) + UtilNodes=object, _py_int_types=object) -if sys.version_info[0] >= 3: - _py_int_types = int +if sys.version_info[0] >= 3: + _py_int_types = int _py_string_types = (bytes, str) -else: - _py_int_types = (int, long) +else: + _py_int_types = (int, long) _py_string_types = (bytes, unicode) - + from . import Nodes from . import ExprNodes from . import PyrexTypes @@ -28,7 +28,7 @@ from . import Builtin from . import UtilNodes from . import Options -from .Code import UtilityCode, TempitaUtilityCode +from .Code import UtilityCode, TempitaUtilityCode from .StringEncoding import EncodedString, bytes_literal, encoded_string from .Errors import error, warning from .ParseTreeTransforms import SkipDeclarations @@ -43,23 +43,23 @@ try: except ImportError: basestring = str # Python 3 - + def load_c_utility(name): return UtilityCode.load_cached(name, "Optimize.c") - + def unwrap_coerced_node(node, coercion_nodes=(ExprNodes.CoerceToPyTypeNode, ExprNodes.CoerceFromPyTypeNode)): if isinstance(node, coercion_nodes): return node.arg return node - + def unwrap_node(node): while isinstance(node, UtilNodes.ResultRefNode): node = node.expression return node - + def is_common_value(a, b): a = unwrap_node(a) b = unwrap_node(b) @@ -69,66 +69,66 @@ def is_common_value(a, b): return not a.is_py_attr and is_common_value(a.obj, b.obj) and a.attribute == b.attribute return False - + def filter_none_node(node): if node is not None and node.constant_result is None: return None return node - -class _YieldNodeCollector(Visitor.TreeVisitor): - """ - YieldExprNode finder for generator expressions. - """ - def __init__(self): - Visitor.TreeVisitor.__init__(self) - self.yield_stat_nodes = {} - self.yield_nodes = [] - - visit_Node = Visitor.TreeVisitor.visitchildren - - def visit_YieldExprNode(self, node): - self.yield_nodes.append(node) - self.visitchildren(node) - - def visit_ExprStatNode(self, node): - self.visitchildren(node) - if node.expr in self.yield_nodes: - self.yield_stat_nodes[node.expr] = node - - # everything below these nodes is out of scope: - - def visit_GeneratorExpressionNode(self, node): - pass - - def visit_LambdaNode(self, node): - pass - - def visit_FuncDefNode(self, node): - pass - - -def _find_single_yield_expression(node): - yield_statements = _find_yield_statements(node) - if len(yield_statements) != 1: - return None, None - return yield_statements[0] - - -def _find_yield_statements(node): - collector = _YieldNodeCollector() - collector.visitchildren(node) - try: - yield_statements = [ - (yield_node.arg, collector.yield_stat_nodes[yield_node]) - for yield_node in collector.yield_nodes - ] - except KeyError: - # found YieldExprNode without ExprStatNode (i.e. a non-statement usage of 'yield') - yield_statements = [] - return yield_statements - - + +class _YieldNodeCollector(Visitor.TreeVisitor): + """ + YieldExprNode finder for generator expressions. + """ + def __init__(self): + Visitor.TreeVisitor.__init__(self) + self.yield_stat_nodes = {} + self.yield_nodes = [] + + visit_Node = Visitor.TreeVisitor.visitchildren + + def visit_YieldExprNode(self, node): + self.yield_nodes.append(node) + self.visitchildren(node) + + def visit_ExprStatNode(self, node): + self.visitchildren(node) + if node.expr in self.yield_nodes: + self.yield_stat_nodes[node.expr] = node + + # everything below these nodes is out of scope: + + def visit_GeneratorExpressionNode(self, node): + pass + + def visit_LambdaNode(self, node): + pass + + def visit_FuncDefNode(self, node): + pass + + +def _find_single_yield_expression(node): + yield_statements = _find_yield_statements(node) + if len(yield_statements) != 1: + return None, None + return yield_statements[0] + + +def _find_yield_statements(node): + collector = _YieldNodeCollector() + collector.visitchildren(node) + try: + yield_statements = [ + (yield_node.arg, collector.yield_stat_nodes[yield_node]) + for yield_node in collector.yield_nodes + ] + except KeyError: + # found YieldExprNode without ExprStatNode (i.e. a non-statement usage of 'yield') + yield_statements = [] + return yield_statements + + class IterationTransform(Visitor.EnvTransform): """Transform some common for-in loop patterns into efficient C loops: @@ -148,7 +148,7 @@ class IterationTransform(Visitor.EnvTransform): pos = node.pos result_ref = UtilNodes.ResultRefNode(node) - if node.operand2.is_subscript: + if node.operand2.is_subscript: base_type = node.operand2.base.type.base_type else: base_type = node.operand2.type.base_type @@ -250,7 +250,7 @@ class IterationTransform(Visitor.EnvTransform): if not is_safe_iter and method in ('keys', 'values', 'items'): # try to reduce this to the corresponding .iter*() methods - if isinstance(base_obj, ExprNodes.CallNode): + if isinstance(base_obj, ExprNodes.CallNode): inner_function = base_obj.function if (inner_function.is_name and inner_function.name == 'dict' and inner_function.entry @@ -391,7 +391,7 @@ class IterationTransform(Visitor.EnvTransform): if slice_node.is_literal: # try to reduce to byte iteration for plain Latin-1 strings try: - bytes_value = bytes_literal(slice_node.value.encode('latin1'), 'iso8859-1') + bytes_value = bytes_literal(slice_node.value.encode('latin1'), 'iso8859-1') except UnicodeEncodeError: pass else: @@ -400,8 +400,8 @@ class IterationTransform(Visitor.EnvTransform): base=ExprNodes.BytesNode( slice_node.pos, value=bytes_value, constant_result=bytes_value, - type=PyrexTypes.c_const_char_ptr_type).coerce_to( - PyrexTypes.c_const_uchar_ptr_type, self.current_env()), + type=PyrexTypes.c_const_char_ptr_type).coerce_to( + PyrexTypes.c_const_uchar_ptr_type, self.current_env()), start=None, stop=ExprNodes.IntNode( slice_node.pos, value=str(len(bytes_value)), @@ -491,7 +491,7 @@ class IterationTransform(Visitor.EnvTransform): error(slice_node.pos, "C array iteration requires known end index") return node - elif slice_node.is_subscript: + elif slice_node.is_subscript: assert isinstance(slice_node.index, ExprNodes.SliceNode) slice_base = slice_node.base index = slice_node.index @@ -499,7 +499,7 @@ class IterationTransform(Visitor.EnvTransform): stop = filter_none_node(index.stop) step = filter_none_node(index.step) if step: - if not isinstance(step.constant_result, _py_int_types) \ + if not isinstance(step.constant_result, _py_int_types) \ or step.constant_result == 0 \ or step.constant_result > 0 and not stop \ or step.constant_result < 0 and not start: @@ -733,19 +733,19 @@ class IterationTransform(Visitor.EnvTransform): if len(args) < 3: step_pos = range_function.pos step_value = 1 - step = ExprNodes.IntNode(step_pos, value='1', constant_result=1) + step = ExprNodes.IntNode(step_pos, value='1', constant_result=1) else: step = args[2] step_pos = step.pos - if not isinstance(step.constant_result, _py_int_types): + if not isinstance(step.constant_result, _py_int_types): # cannot determine step direction return node step_value = step.constant_result if step_value == 0: # will lead to an error elsewhere return node - step = ExprNodes.IntNode(step_pos, value=str(step_value), - constant_result=step_value) + step = ExprNodes.IntNode(step_pos, value=str(step_value), + constant_result=step_value) if len(args) == 1: bound1 = ExprNodes.IntNode(range_function.pos, value='0', @@ -757,34 +757,34 @@ class IterationTransform(Visitor.EnvTransform): relation1, relation2 = self._find_for_from_node_relations(step_value < 0, reversed) - bound2_ref_node = None + bound2_ref_node = None if reversed: bound1, bound2 = bound2, bound1 - abs_step = abs(step_value) - if abs_step != 1: - if (isinstance(bound1.constant_result, _py_int_types) and - isinstance(bound2.constant_result, _py_int_types)): - # calculate final bounds now - if step_value < 0: - begin_value = bound2.constant_result - end_value = bound1.constant_result - bound1_value = begin_value - abs_step * ((begin_value - end_value - 1) // abs_step) - 1 - else: - begin_value = bound1.constant_result - end_value = bound2.constant_result - bound1_value = end_value + abs_step * ((begin_value - end_value - 1) // abs_step) + 1 - - bound1 = ExprNodes.IntNode( - bound1.pos, value=str(bound1_value), constant_result=bound1_value, - type=PyrexTypes.spanning_type(bound1.type, bound2.type)) - else: - # evaluate the same expression as above at runtime - bound2_ref_node = UtilNodes.LetRefNode(bound2) - bound1 = self._build_range_step_calculation( - bound1, bound2_ref_node, step, step_value) - - if step_value < 0: - step_value = -step_value + abs_step = abs(step_value) + if abs_step != 1: + if (isinstance(bound1.constant_result, _py_int_types) and + isinstance(bound2.constant_result, _py_int_types)): + # calculate final bounds now + if step_value < 0: + begin_value = bound2.constant_result + end_value = bound1.constant_result + bound1_value = begin_value - abs_step * ((begin_value - end_value - 1) // abs_step) - 1 + else: + begin_value = bound1.constant_result + end_value = bound2.constant_result + bound1_value = end_value + abs_step * ((begin_value - end_value - 1) // abs_step) + 1 + + bound1 = ExprNodes.IntNode( + bound1.pos, value=str(bound1_value), constant_result=bound1_value, + type=PyrexTypes.spanning_type(bound1.type, bound2.type)) + else: + # evaluate the same expression as above at runtime + bound2_ref_node = UtilNodes.LetRefNode(bound2) + bound1 = self._build_range_step_calculation( + bound1, bound2_ref_node, step, step_value) + + if step_value < 0: + step_value = -step_value step.value = str(step_value) step.constant_result = step_value step = step.coerce_to_integer(self.current_env()) @@ -792,7 +792,7 @@ class IterationTransform(Visitor.EnvTransform): if not bound2.is_literal: # stop bound must be immutable => keep it in a temp var bound2_is_temp = True - bound2 = bound2_ref_node or UtilNodes.LetRefNode(bound2) + bound2 = bound2_ref_node or UtilNodes.LetRefNode(bound2) else: bound2_is_temp = False @@ -811,70 +811,70 @@ class IterationTransform(Visitor.EnvTransform): return for_node - def _build_range_step_calculation(self, bound1, bound2_ref_node, step, step_value): - abs_step = abs(step_value) - spanning_type = PyrexTypes.spanning_type(bound1.type, bound2_ref_node.type) - if step.type.is_int and abs_step < 0x7FFF: - # Avoid loss of integer precision warnings. - spanning_step_type = PyrexTypes.spanning_type(spanning_type, PyrexTypes.c_int_type) - else: - spanning_step_type = PyrexTypes.spanning_type(spanning_type, step.type) - if step_value < 0: - begin_value = bound2_ref_node - end_value = bound1 - final_op = '-' - else: - begin_value = bound1 - end_value = bound2_ref_node - final_op = '+' - - step_calculation_node = ExprNodes.binop_node( - bound1.pos, - operand1=ExprNodes.binop_node( - bound1.pos, - operand1=bound2_ref_node, - operator=final_op, # +/- - operand2=ExprNodes.MulNode( - bound1.pos, - operand1=ExprNodes.IntNode( - bound1.pos, - value=str(abs_step), - constant_result=abs_step, - type=spanning_step_type), - operator='*', - operand2=ExprNodes.DivNode( - bound1.pos, - operand1=ExprNodes.SubNode( - bound1.pos, - operand1=ExprNodes.SubNode( - bound1.pos, - operand1=begin_value, - operator='-', - operand2=end_value, - type=spanning_type), - operator='-', - operand2=ExprNodes.IntNode( - bound1.pos, - value='1', - constant_result=1), - type=spanning_step_type), - operator='//', - operand2=ExprNodes.IntNode( - bound1.pos, - value=str(abs_step), - constant_result=abs_step, - type=spanning_step_type), - type=spanning_step_type), - type=spanning_step_type), - type=spanning_step_type), - operator=final_op, # +/- - operand2=ExprNodes.IntNode( - bound1.pos, - value='1', - constant_result=1), - type=spanning_type) - return step_calculation_node - + def _build_range_step_calculation(self, bound1, bound2_ref_node, step, step_value): + abs_step = abs(step_value) + spanning_type = PyrexTypes.spanning_type(bound1.type, bound2_ref_node.type) + if step.type.is_int and abs_step < 0x7FFF: + # Avoid loss of integer precision warnings. + spanning_step_type = PyrexTypes.spanning_type(spanning_type, PyrexTypes.c_int_type) + else: + spanning_step_type = PyrexTypes.spanning_type(spanning_type, step.type) + if step_value < 0: + begin_value = bound2_ref_node + end_value = bound1 + final_op = '-' + else: + begin_value = bound1 + end_value = bound2_ref_node + final_op = '+' + + step_calculation_node = ExprNodes.binop_node( + bound1.pos, + operand1=ExprNodes.binop_node( + bound1.pos, + operand1=bound2_ref_node, + operator=final_op, # +/- + operand2=ExprNodes.MulNode( + bound1.pos, + operand1=ExprNodes.IntNode( + bound1.pos, + value=str(abs_step), + constant_result=abs_step, + type=spanning_step_type), + operator='*', + operand2=ExprNodes.DivNode( + bound1.pos, + operand1=ExprNodes.SubNode( + bound1.pos, + operand1=ExprNodes.SubNode( + bound1.pos, + operand1=begin_value, + operator='-', + operand2=end_value, + type=spanning_type), + operator='-', + operand2=ExprNodes.IntNode( + bound1.pos, + value='1', + constant_result=1), + type=spanning_step_type), + operator='//', + operand2=ExprNodes.IntNode( + bound1.pos, + value=str(abs_step), + constant_result=abs_step, + type=spanning_step_type), + type=spanning_step_type), + type=spanning_step_type), + type=spanning_step_type), + operator=final_op, # +/- + operand2=ExprNodes.IntNode( + bound1.pos, + value='1', + constant_result=1), + type=spanning_type) + return step_calculation_node + def _transform_dict_iteration(self, node, dict_obj, method, keys, values): temps = [] temp = UtilNodes.TempHandle(PyrexTypes.py_object_type) @@ -1192,9 +1192,9 @@ class SwitchTransform(Visitor.EnvTransform): if common_var is None: self.visitchildren(node) return node - cases.append(Nodes.SwitchCaseNode(pos=if_clause.pos, - conditions=conditions, - body=if_clause.body)) + cases.append(Nodes.SwitchCaseNode(pos=if_clause.pos, + conditions=conditions, + body=if_clause.body)) condition_values = [ cond for case in cases for cond in case.conditions] @@ -1205,16 +1205,16 @@ class SwitchTransform(Visitor.EnvTransform): self.visitchildren(node) return node - # Recurse into body subtrees that we left untouched so far. - self.visitchildren(node, 'else_clause') - for case in cases: - self.visitchildren(case, 'body') - + # Recurse into body subtrees that we left untouched so far. + self.visitchildren(node, 'else_clause') + for case in cases: + self.visitchildren(case, 'body') + common_var = unwrap_node(common_var) - switch_node = Nodes.SwitchStatNode(pos=node.pos, - test=common_var, - cases=cases, - else_clause=node.else_clause) + switch_node = Nodes.SwitchStatNode(pos=node.pos, + test=common_var, + cases=cases, + else_clause=node.else_clause) return switch_node def visit_CondExprNode(self, node): @@ -1225,11 +1225,11 @@ class SwitchTransform(Visitor.EnvTransform): not_in, common_var, conditions = self.extract_common_conditions( None, node.test, True) if common_var is None \ - or len(conditions) < 2 \ - or self.has_duplicate_values(conditions): + or len(conditions) < 2 \ + or self.has_duplicate_values(conditions): self.visitchildren(node) return node - + return self.build_simple_switch_statement( node, common_var, conditions, not_in, node.true_val, node.false_val) @@ -1242,8 +1242,8 @@ class SwitchTransform(Visitor.EnvTransform): not_in, common_var, conditions = self.extract_common_conditions( None, node, True) if common_var is None \ - or len(conditions) < 2 \ - or self.has_duplicate_values(conditions): + or len(conditions) < 2 \ + or self.has_duplicate_values(conditions): self.visitchildren(node) node.wrap_operands(self.current_env()) # in case we changed the operands return node @@ -1261,8 +1261,8 @@ class SwitchTransform(Visitor.EnvTransform): not_in, common_var, conditions = self.extract_common_conditions( None, node, True) if common_var is None \ - or len(conditions) < 2 \ - or self.has_duplicate_values(conditions): + or len(conditions) < 2 \ + or self.has_duplicate_values(conditions): self.visitchildren(node) return node @@ -1477,20 +1477,20 @@ class DropRefcountingTransform(Visitor.VisitorTransform): node = node.arg name_path = [] obj_node = node - while obj_node.is_attribute: + while obj_node.is_attribute: if obj_node.is_py_attr: return False name_path.append(obj_node.member) obj_node = obj_node.obj - if obj_node.is_name: + if obj_node.is_name: name_path.append(obj_node.name) names.append( ('.'.join(name_path[::-1]), node) ) - elif node.is_subscript: + elif node.is_subscript: if node.base.type != Builtin.list_type: return False if not node.index.type.is_int: return False - if not node.base.is_name: + if not node.base.is_name: return False indices.append(node) else: @@ -1618,60 +1618,60 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform): stop=stop, step=step or ExprNodes.NoneNode(node.pos)) - def _handle_simple_function_ord(self, node, pos_args): - """Unpack ord('X'). - """ - if len(pos_args) != 1: - return node - arg = pos_args[0] - if isinstance(arg, (ExprNodes.UnicodeNode, ExprNodes.BytesNode)): - if len(arg.value) == 1: - return ExprNodes.IntNode( - arg.pos, type=PyrexTypes.c_long_type, - value=str(ord(arg.value)), - constant_result=ord(arg.value) - ) - elif isinstance(arg, ExprNodes.StringNode): - if arg.unicode_value and len(arg.unicode_value) == 1 \ - and ord(arg.unicode_value) <= 255: # Py2/3 portability - return ExprNodes.IntNode( - arg.pos, type=PyrexTypes.c_int_type, - value=str(ord(arg.unicode_value)), - constant_result=ord(arg.unicode_value) - ) - return node - - # sequence processing + def _handle_simple_function_ord(self, node, pos_args): + """Unpack ord('X'). + """ + if len(pos_args) != 1: + return node + arg = pos_args[0] + if isinstance(arg, (ExprNodes.UnicodeNode, ExprNodes.BytesNode)): + if len(arg.value) == 1: + return ExprNodes.IntNode( + arg.pos, type=PyrexTypes.c_long_type, + value=str(ord(arg.value)), + constant_result=ord(arg.value) + ) + elif isinstance(arg, ExprNodes.StringNode): + if arg.unicode_value and len(arg.unicode_value) == 1 \ + and ord(arg.unicode_value) <= 255: # Py2/3 portability + return ExprNodes.IntNode( + arg.pos, type=PyrexTypes.c_int_type, + value=str(ord(arg.unicode_value)), + constant_result=ord(arg.unicode_value) + ) + return node + + # sequence processing def _handle_simple_function_all(self, node, pos_args): """Transform - _result = all(p(x) for L in LL for x in L) + _result = all(p(x) for L in LL for x in L) into for L in LL: for x in L: - if not p(x): - return False + if not p(x): + return False else: - return True + return True """ return self._transform_any_all(node, pos_args, False) def _handle_simple_function_any(self, node, pos_args): """Transform - _result = any(p(x) for L in LL for x in L) + _result = any(p(x) for L in LL for x in L) into for L in LL: for x in L: - if p(x): - return True + if p(x): + return True else: - return False + return False """ return self._transform_any_all(node, pos_args, True) @@ -1681,40 +1681,40 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform): if not isinstance(pos_args[0], ExprNodes.GeneratorExpressionNode): return node gen_expr_node = pos_args[0] - generator_body = gen_expr_node.def_node.gbody - loop_node = generator_body.body - yield_expression, yield_stat_node = _find_single_yield_expression(loop_node) + generator_body = gen_expr_node.def_node.gbody + loop_node = generator_body.body + yield_expression, yield_stat_node = _find_single_yield_expression(loop_node) if yield_expression is None: return node if is_any: condition = yield_expression else: - condition = ExprNodes.NotNode(yield_expression.pos, operand=yield_expression) + condition = ExprNodes.NotNode(yield_expression.pos, operand=yield_expression) test_node = Nodes.IfStatNode( - yield_expression.pos, else_clause=None, if_clauses=[ - Nodes.IfClauseNode( - yield_expression.pos, - condition=condition, - body=Nodes.ReturnStatNode( - node.pos, - value=ExprNodes.BoolNode(yield_expression.pos, value=is_any, constant_result=is_any)) - )] - ) - loop_node.else_clause = Nodes.ReturnStatNode( + yield_expression.pos, else_clause=None, if_clauses=[ + Nodes.IfClauseNode( + yield_expression.pos, + condition=condition, + body=Nodes.ReturnStatNode( + node.pos, + value=ExprNodes.BoolNode(yield_expression.pos, value=is_any, constant_result=is_any)) + )] + ) + loop_node.else_clause = Nodes.ReturnStatNode( node.pos, - value=ExprNodes.BoolNode(yield_expression.pos, value=not is_any, constant_result=not is_any)) + value=ExprNodes.BoolNode(yield_expression.pos, value=not is_any, constant_result=not is_any)) - Visitor.recursively_replace_node(gen_expr_node, yield_stat_node, test_node) + Visitor.recursively_replace_node(gen_expr_node, yield_stat_node, test_node) return ExprNodes.InlinedGeneratorExpressionNode( - gen_expr_node.pos, gen=gen_expr_node, orig_func='any' if is_any else 'all') + gen_expr_node.pos, gen=gen_expr_node, orig_func='any' if is_any else 'all') + + PySequence_List_func_type = PyrexTypes.CFuncType( + Builtin.list_type, + [PyrexTypes.CFuncTypeArg("it", PyrexTypes.py_object_type, None)]) - PySequence_List_func_type = PyrexTypes.CFuncType( - Builtin.list_type, - [PyrexTypes.CFuncTypeArg("it", PyrexTypes.py_object_type, None)]) - def _handle_simple_function_sorted(self, node, pos_args): """Transform sorted(genexpr) and sorted([listcomp]) into [listcomp].sort(). CPython just reads the iterable into a @@ -1724,62 +1724,62 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform): """ if len(pos_args) != 1: return node - - arg = pos_args[0] - if isinstance(arg, ExprNodes.ComprehensionNode) and arg.type is Builtin.list_type: - list_node = pos_args[0] - loop_node = list_node.loop - - elif isinstance(arg, ExprNodes.GeneratorExpressionNode): - gen_expr_node = arg + + arg = pos_args[0] + if isinstance(arg, ExprNodes.ComprehensionNode) and arg.type is Builtin.list_type: + list_node = pos_args[0] + loop_node = list_node.loop + + elif isinstance(arg, ExprNodes.GeneratorExpressionNode): + gen_expr_node = arg loop_node = gen_expr_node.loop - yield_statements = _find_yield_statements(loop_node) - if not yield_statements: + yield_statements = _find_yield_statements(loop_node) + if not yield_statements: return node - list_node = ExprNodes.InlinedGeneratorExpressionNode( - node.pos, gen_expr_node, orig_func='sorted', - comprehension_type=Builtin.list_type) - - for yield_expression, yield_stat_node in yield_statements: - append_node = ExprNodes.ComprehensionAppendNode( - yield_expression.pos, - expr=yield_expression, - target=list_node.target) - Visitor.recursively_replace_node(gen_expr_node, yield_stat_node, append_node) - - elif arg.is_sequence_constructor: - # sorted([a, b, c]) or sorted((a, b, c)). The result is always a list, - # so starting off with a fresh one is more efficient. - list_node = loop_node = arg.as_list() - + list_node = ExprNodes.InlinedGeneratorExpressionNode( + node.pos, gen_expr_node, orig_func='sorted', + comprehension_type=Builtin.list_type) + + for yield_expression, yield_stat_node in yield_statements: + append_node = ExprNodes.ComprehensionAppendNode( + yield_expression.pos, + expr=yield_expression, + target=list_node.target) + Visitor.recursively_replace_node(gen_expr_node, yield_stat_node, append_node) + + elif arg.is_sequence_constructor: + # sorted([a, b, c]) or sorted((a, b, c)). The result is always a list, + # so starting off with a fresh one is more efficient. + list_node = loop_node = arg.as_list() + else: - # Interestingly, PySequence_List works on a lot of non-sequence - # things as well. - list_node = loop_node = ExprNodes.PythonCapiCallNode( - node.pos, "PySequence_List", self.PySequence_List_func_type, - args=pos_args, is_temp=True) + # Interestingly, PySequence_List works on a lot of non-sequence + # things as well. + list_node = loop_node = ExprNodes.PythonCapiCallNode( + node.pos, "PySequence_List", self.PySequence_List_func_type, + args=pos_args, is_temp=True) result_node = UtilNodes.ResultRefNode( - pos=loop_node.pos, type=Builtin.list_type, may_hold_none=False) - list_assign_node = Nodes.SingleAssignmentNode( - node.pos, lhs=result_node, rhs=list_node, first=True) + pos=loop_node.pos, type=Builtin.list_type, may_hold_none=False) + list_assign_node = Nodes.SingleAssignmentNode( + node.pos, lhs=result_node, rhs=list_node, first=True) sort_method = ExprNodes.AttributeNode( - node.pos, obj=result_node, attribute=EncodedString('sort'), + node.pos, obj=result_node, attribute=EncodedString('sort'), # entry ? type ? - needs_none_check=False) + needs_none_check=False) sort_node = Nodes.ExprStatNode( - node.pos, expr=ExprNodes.SimpleCallNode( - node.pos, function=sort_method, args=[])) + node.pos, expr=ExprNodes.SimpleCallNode( + node.pos, function=sort_method, args=[])) sort_node.analyse_declarations(self.current_env()) return UtilNodes.TempResultFromStatNode( result_node, - Nodes.StatListNode(node.pos, stats=[list_assign_node, sort_node])) + Nodes.StatListNode(node.pos, stats=[list_assign_node, sort_node])) - def __handle_simple_function_sum(self, node, pos_args): + def __handle_simple_function_sum(self, node, pos_args): """Transform sum(genexpr) into an equivalent inlined aggregation loop. """ if len(pos_args) not in (1,2): @@ -1791,12 +1791,12 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform): loop_node = gen_expr_node.loop if isinstance(gen_expr_node, ExprNodes.GeneratorExpressionNode): - yield_expression, yield_stat_node = _find_single_yield_expression(loop_node) - # FIXME: currently nonfunctional - yield_expression = None + yield_expression, yield_stat_node = _find_single_yield_expression(loop_node) + # FIXME: currently nonfunctional + yield_expression = None if yield_expression is None: return node - else: # ComprehensionNode + else: # ComprehensionNode yield_stat_node = gen_expr_node.append yield_expression = yield_stat_node.expr try: @@ -1819,7 +1819,7 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform): rhs = ExprNodes.binop_node(node.pos, '+', result_ref, yield_expression) ) - Visitor.recursively_replace_node(gen_expr_node, yield_stat_node, add_node) + Visitor.recursively_replace_node(gen_expr_node, yield_stat_node, add_node) exec_code = Nodes.StatListNode( node.pos, @@ -1849,7 +1849,7 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform): if len(args) <= 1: if len(args) == 1 and args[0].is_sequence_constructor: args = args[0].args - if len(args) <= 1: + if len(args) <= 1: # leave this to Python return node @@ -1876,8 +1876,8 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform): return last_result - # builtin type creation - + # builtin type creation + def _DISABLED_handle_simple_function_tuple(self, node, pos_args): if not pos_args: return ExprNodes.TupleNode(node.pos, args=[], constant_result=()) @@ -1915,7 +1915,7 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform): return self._transform_list_set_genexpr(node, pos_args, Builtin.set_type) def _transform_list_set_genexpr(self, node, pos_args, target_type): - """Replace set(genexpr) and list(genexpr) by an inlined comprehension. + """Replace set(genexpr) and list(genexpr) by an inlined comprehension. """ if len(pos_args) > 1: return node @@ -1924,26 +1924,26 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform): gen_expr_node = pos_args[0] loop_node = gen_expr_node.loop - yield_statements = _find_yield_statements(loop_node) - if not yield_statements: + yield_statements = _find_yield_statements(loop_node) + if not yield_statements: return node - result_node = ExprNodes.InlinedGeneratorExpressionNode( - node.pos, gen_expr_node, - orig_func='set' if target_type is Builtin.set_type else 'list', - comprehension_type=target_type) - - for yield_expression, yield_stat_node in yield_statements: - append_node = ExprNodes.ComprehensionAppendNode( - yield_expression.pos, - expr=yield_expression, - target=result_node.target) - Visitor.recursively_replace_node(gen_expr_node, yield_stat_node, append_node) + result_node = ExprNodes.InlinedGeneratorExpressionNode( + node.pos, gen_expr_node, + orig_func='set' if target_type is Builtin.set_type else 'list', + comprehension_type=target_type) - return result_node + for yield_expression, yield_stat_node in yield_statements: + append_node = ExprNodes.ComprehensionAppendNode( + yield_expression.pos, + expr=yield_expression, + target=result_node.target) + Visitor.recursively_replace_node(gen_expr_node, yield_stat_node, append_node) + + return result_node def _handle_simple_function_dict(self, node, pos_args): - """Replace dict( (a,b) for ... ) by an inlined { a:b for ... } + """Replace dict( (a,b) for ... ) by an inlined { a:b for ... } """ if len(pos_args) == 0: return ExprNodes.DictNode(node.pos, key_value_pairs=[], constant_result={}) @@ -1954,29 +1954,29 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform): gen_expr_node = pos_args[0] loop_node = gen_expr_node.loop - yield_statements = _find_yield_statements(loop_node) - if not yield_statements: + yield_statements = _find_yield_statements(loop_node) + if not yield_statements: return node - for yield_expression, _ in yield_statements: - if not isinstance(yield_expression, ExprNodes.TupleNode): - return node - if len(yield_expression.args) != 2: - return node + for yield_expression, _ in yield_statements: + if not isinstance(yield_expression, ExprNodes.TupleNode): + return node + if len(yield_expression.args) != 2: + return node + + result_node = ExprNodes.InlinedGeneratorExpressionNode( + node.pos, gen_expr_node, orig_func='dict', + comprehension_type=Builtin.dict_type) - result_node = ExprNodes.InlinedGeneratorExpressionNode( - node.pos, gen_expr_node, orig_func='dict', - comprehension_type=Builtin.dict_type) - - for yield_expression, yield_stat_node in yield_statements: - append_node = ExprNodes.DictComprehensionAppendNode( - yield_expression.pos, - key_expr=yield_expression.args[0], - value_expr=yield_expression.args[1], - target=result_node.target) - Visitor.recursively_replace_node(gen_expr_node, yield_stat_node, append_node) + for yield_expression, yield_stat_node in yield_statements: + append_node = ExprNodes.DictComprehensionAppendNode( + yield_expression.pos, + key_expr=yield_expression.args[0], + value_expr=yield_expression.args[1], + target=result_node.target) + Visitor.recursively_replace_node(gen_expr_node, yield_stat_node, append_node) - return result_node + return result_node # specific handlers for general call nodes @@ -2024,8 +2024,8 @@ class InlineDefNodeCalls(Visitor.NodeRefCleanupMixin, Visitor.EnvTransform): return node -class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, - Visitor.MethodDispatcherTransform): +class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, + Visitor.MethodDispatcherTransform): """Optimize some common methods calls and instantiation patterns for builtin types *after* the type analysis phase. @@ -2080,33 +2080,33 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, return arg.arg.coerce_to_boolean(self.current_env()) return node - PyNumber_Float_func_type = PyrexTypes.CFuncType( - PyrexTypes.py_object_type, [ - PyrexTypes.CFuncTypeArg("o", PyrexTypes.py_object_type, None) - ]) - - def visit_CoerceToPyTypeNode(self, node): - """Drop redundant conversion nodes after tree changes.""" - self.visitchildren(node) - arg = node.arg - if isinstance(arg, ExprNodes.CoerceFromPyTypeNode): - arg = arg.arg - if isinstance(arg, ExprNodes.PythonCapiCallNode): - if arg.function.name == 'float' and len(arg.args) == 1: - # undo redundant Py->C->Py coercion - func_arg = arg.args[0] - if func_arg.type is Builtin.float_type: - return func_arg.as_none_safe_node("float() argument must be a string or a number, not 'NoneType'") - elif func_arg.type.is_pyobject: - return ExprNodes.PythonCapiCallNode( - node.pos, '__Pyx_PyNumber_Float', self.PyNumber_Float_func_type, - args=[func_arg], - py_name='float', - is_temp=node.is_temp, - result_is_used=node.result_is_used, - ).coerce_to(node.type, self.current_env()) - return node - + PyNumber_Float_func_type = PyrexTypes.CFuncType( + PyrexTypes.py_object_type, [ + PyrexTypes.CFuncTypeArg("o", PyrexTypes.py_object_type, None) + ]) + + def visit_CoerceToPyTypeNode(self, node): + """Drop redundant conversion nodes after tree changes.""" + self.visitchildren(node) + arg = node.arg + if isinstance(arg, ExprNodes.CoerceFromPyTypeNode): + arg = arg.arg + if isinstance(arg, ExprNodes.PythonCapiCallNode): + if arg.function.name == 'float' and len(arg.args) == 1: + # undo redundant Py->C->Py coercion + func_arg = arg.args[0] + if func_arg.type is Builtin.float_type: + return func_arg.as_none_safe_node("float() argument must be a string or a number, not 'NoneType'") + elif func_arg.type.is_pyobject: + return ExprNodes.PythonCapiCallNode( + node.pos, '__Pyx_PyNumber_Float', self.PyNumber_Float_func_type, + args=[func_arg], + py_name='float', + is_temp=node.is_temp, + result_is_used=node.result_is_used, + ).coerce_to(node.type, self.current_env()) + return node + def visit_CoerceFromPyTypeNode(self, node): """Drop redundant conversion nodes after tree changes. @@ -2118,9 +2118,9 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, arg = node.arg if not arg.type.is_pyobject: # no Python conversion left at all, just do a C coercion instead - if node.type != arg.type: - arg = arg.coerce_to(node.type, self.current_env()) - return arg + if node.type != arg.type: + arg = arg.coerce_to(node.type, self.current_env()) + return arg if isinstance(arg, ExprNodes.PyTypeTestNode): arg = arg.arg if arg.is_literal: @@ -2133,13 +2133,13 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, if node.type.assignable_from(arg.arg.type): # completely redundant C->Py->C coercion return arg.arg.coerce_to(node.type, self.current_env()) - elif arg.type is Builtin.unicode_type: - if arg.arg.type.is_unicode_char and node.type.is_unicode_char: - return arg.arg.coerce_to(node.type, self.current_env()) + elif arg.type is Builtin.unicode_type: + if arg.arg.type.is_unicode_char and node.type.is_unicode_char: + return arg.arg.coerce_to(node.type, self.current_env()) elif isinstance(arg, ExprNodes.SimpleCallNode): if node.type.is_int or node.type.is_float: return self._optimise_numeric_cast_call(node, arg) - elif arg.is_subscript: + elif arg.is_subscript: index_node = arg.index if isinstance(index_node, ExprNodes.CoerceToPyTypeNode): index_node = index_node.arg @@ -2181,51 +2181,51 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, return node return coerce_node - float_float_func_types = dict( - (float_type, PyrexTypes.CFuncType( - float_type, [ - PyrexTypes.CFuncTypeArg("arg", float_type, None) - ])) - for float_type in (PyrexTypes.c_float_type, PyrexTypes.c_double_type, PyrexTypes.c_longdouble_type)) - + float_float_func_types = dict( + (float_type, PyrexTypes.CFuncType( + float_type, [ + PyrexTypes.CFuncTypeArg("arg", float_type, None) + ])) + for float_type in (PyrexTypes.c_float_type, PyrexTypes.c_double_type, PyrexTypes.c_longdouble_type)) + def _optimise_numeric_cast_call(self, node, arg): function = arg.function - args = None - if isinstance(arg, ExprNodes.PythonCapiCallNode): - args = arg.args - elif isinstance(function, ExprNodes.NameNode): - if function.type.is_builtin_type and isinstance(arg.arg_tuple, ExprNodes.TupleNode): - args = arg.arg_tuple.args - - if args is None or len(args) != 1: + args = None + if isinstance(arg, ExprNodes.PythonCapiCallNode): + args = arg.args + elif isinstance(function, ExprNodes.NameNode): + if function.type.is_builtin_type and isinstance(arg.arg_tuple, ExprNodes.TupleNode): + args = arg.arg_tuple.args + + if args is None or len(args) != 1: return node func_arg = args[0] if isinstance(func_arg, ExprNodes.CoerceToPyTypeNode): func_arg = func_arg.arg elif func_arg.type.is_pyobject: - # play it safe: Python conversion might work on all sorts of things + # play it safe: Python conversion might work on all sorts of things return node - + if function.name == 'int': if func_arg.type.is_int or node.type.is_int: if func_arg.type == node.type: return func_arg elif node.type.assignable_from(func_arg.type) or func_arg.type.is_float: - return ExprNodes.TypecastNode(node.pos, operand=func_arg, type=node.type) - elif func_arg.type.is_float and node.type.is_numeric: - if func_arg.type.math_h_modifier == 'l': - # Work around missing Cygwin definition. - truncl = '__Pyx_truncl' - else: - truncl = 'trunc' + func_arg.type.math_h_modifier - return ExprNodes.PythonCapiCallNode( - node.pos, truncl, - func_type=self.float_float_func_types[func_arg.type], - args=[func_arg], - py_name='int', - is_temp=node.is_temp, - result_is_used=node.result_is_used, - ).coerce_to(node.type, self.current_env()) + return ExprNodes.TypecastNode(node.pos, operand=func_arg, type=node.type) + elif func_arg.type.is_float and node.type.is_numeric: + if func_arg.type.math_h_modifier == 'l': + # Work around missing Cygwin definition. + truncl = '__Pyx_truncl' + else: + truncl = 'trunc' + func_arg.type.math_h_modifier + return ExprNodes.PythonCapiCallNode( + node.pos, truncl, + func_type=self.float_float_func_types[func_arg.type], + args=[func_arg], + py_name='int', + is_temp=node.is_temp, + result_is_used=node.result_is_used, + ).coerce_to(node.type, self.current_env()) elif function.name == 'float': if func_arg.type.is_float or node.type.is_float: if func_arg.type == node.type: @@ -2281,7 +2281,7 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, entry=type_entry, type=type_entry.type), attribute=attr_name, - is_called=True).analyse_as_type_attribute(self.current_env()) + is_called=True).analyse_as_type_attribute(self.current_env()) if method is None: return self._optimise_generic_builtin_method_call( node, attr_name, function, arg_list, is_unbound_method) @@ -2376,41 +2376,41 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, ) return node - PySequence_List_func_type = PyrexTypes.CFuncType( - Builtin.list_type, - [PyrexTypes.CFuncTypeArg("it", PyrexTypes.py_object_type, None)]) - - def _handle_simple_function_list(self, node, function, pos_args): - """Turn list(ob) into PySequence_List(ob). - """ - if len(pos_args) != 1: - return node - arg = pos_args[0] - return ExprNodes.PythonCapiCallNode( - node.pos, "PySequence_List", self.PySequence_List_func_type, - args=pos_args, is_temp=node.is_temp) - + PySequence_List_func_type = PyrexTypes.CFuncType( + Builtin.list_type, + [PyrexTypes.CFuncTypeArg("it", PyrexTypes.py_object_type, None)]) + + def _handle_simple_function_list(self, node, function, pos_args): + """Turn list(ob) into PySequence_List(ob). + """ + if len(pos_args) != 1: + return node + arg = pos_args[0] + return ExprNodes.PythonCapiCallNode( + node.pos, "PySequence_List", self.PySequence_List_func_type, + args=pos_args, is_temp=node.is_temp) + PyList_AsTuple_func_type = PyrexTypes.CFuncType( Builtin.tuple_type, [ PyrexTypes.CFuncTypeArg("list", Builtin.list_type, None) ]) def _handle_simple_function_tuple(self, node, function, pos_args): - """Replace tuple([...]) by PyList_AsTuple or PySequence_Tuple. + """Replace tuple([...]) by PyList_AsTuple or PySequence_Tuple. """ if len(pos_args) != 1 or not node.is_temp: return node arg = pos_args[0] if arg.type is Builtin.tuple_type and not arg.may_be_none(): return arg - if arg.type is Builtin.list_type: - pos_args[0] = arg.as_none_safe_node( - "'NoneType' object is not iterable") - - return ExprNodes.PythonCapiCallNode( - node.pos, "PyList_AsTuple", self.PyList_AsTuple_func_type, - args=pos_args, is_temp=node.is_temp) - else: + if arg.type is Builtin.list_type: + pos_args[0] = arg.as_none_safe_node( + "'NoneType' object is not iterable") + + return ExprNodes.PythonCapiCallNode( + node.pos, "PyList_AsTuple", self.PyList_AsTuple_func_type, + args=pos_args, is_temp=node.is_temp) + else: return ExprNodes.AsTupleNode(node.pos, arg=arg, type=Builtin.tuple_type) PySet_New_func_type = PyrexTypes.CFuncType( @@ -2435,18 +2435,18 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, temps.append(arg) args.append(arg) result = ExprNodes.SetNode(node.pos, is_temp=1, args=args) - self.replace(node, result) + self.replace(node, result) for temp in temps[::-1]: result = UtilNodes.EvalWithTempExprNode(temp, result) return result else: # PySet_New(it) is better than a generic Python call to set(it) - return self.replace(node, ExprNodes.PythonCapiCallNode( + return self.replace(node, ExprNodes.PythonCapiCallNode( node.pos, "PySet_New", self.PySet_New_func_type, args=pos_args, is_temp=node.is_temp, - py_name="set")) + py_name="set")) PyFrozenSet_New_func_type = PyrexTypes.CFuncType( Builtin.frozenset_type, [ @@ -2510,11 +2510,11 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, PyrexTypes.CFuncTypeArg("o", PyrexTypes.py_object_type, None) ]) - PyInt_FromDouble_func_type = PyrexTypes.CFuncType( - PyrexTypes.py_object_type, [ - PyrexTypes.CFuncTypeArg("value", PyrexTypes.c_double_type, None) - ]) - + PyInt_FromDouble_func_type = PyrexTypes.CFuncType( + PyrexTypes.py_object_type, [ + PyrexTypes.CFuncTypeArg("value", PyrexTypes.c_double_type, None) + ]) + def _handle_simple_function_int(self, node, function, pos_args): """Transform int() into a faster C function call. """ @@ -2525,17 +2525,17 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, return node # int(x, base) func_arg = pos_args[0] if isinstance(func_arg, ExprNodes.CoerceToPyTypeNode): - if func_arg.arg.type.is_float: - return ExprNodes.PythonCapiCallNode( - node.pos, "__Pyx_PyInt_FromDouble", self.PyInt_FromDouble_func_type, - args=[func_arg.arg], is_temp=True, py_name='int', - utility_code=UtilityCode.load_cached("PyIntFromDouble", "TypeConversion.c")) - else: - return node # handled in visit_CoerceFromPyTypeNode() + if func_arg.arg.type.is_float: + return ExprNodes.PythonCapiCallNode( + node.pos, "__Pyx_PyInt_FromDouble", self.PyInt_FromDouble_func_type, + args=[func_arg.arg], is_temp=True, py_name='int', + utility_code=UtilityCode.load_cached("PyIntFromDouble", "TypeConversion.c")) + else: + return node # handled in visit_CoerceFromPyTypeNode() if func_arg.type.is_pyobject and node.type.is_pyobject: return ExprNodes.PythonCapiCallNode( - node.pos, "__Pyx_PyNumber_Int", self.PyNumber_Int_func_type, - args=pos_args, is_temp=True, py_name='int') + node.pos, "__Pyx_PyNumber_Int", self.PyNumber_Int_func_type, + args=pos_args, is_temp=True, py_name='int') return node def _handle_simple_function_bool(self, node, function, pos_args): @@ -2560,30 +2560,30 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, Pyx_strlen_func_type = PyrexTypes.CFuncType( PyrexTypes.c_size_t_type, [ - PyrexTypes.CFuncTypeArg("bytes", PyrexTypes.c_const_char_ptr_type, None) - ]) + PyrexTypes.CFuncTypeArg("bytes", PyrexTypes.c_const_char_ptr_type, None) + ]) Pyx_Py_UNICODE_strlen_func_type = PyrexTypes.CFuncType( PyrexTypes.c_size_t_type, [ - PyrexTypes.CFuncTypeArg("unicode", PyrexTypes.c_const_py_unicode_ptr_type, None) - ]) + PyrexTypes.CFuncTypeArg("unicode", PyrexTypes.c_const_py_unicode_ptr_type, None) + ]) PyObject_Size_func_type = PyrexTypes.CFuncType( PyrexTypes.c_py_ssize_t_type, [ PyrexTypes.CFuncTypeArg("obj", PyrexTypes.py_object_type, None) - ], + ], exception_value="-1") _map_to_capi_len_function = { - Builtin.unicode_type: "__Pyx_PyUnicode_GET_LENGTH", - Builtin.bytes_type: "PyBytes_GET_SIZE", + Builtin.unicode_type: "__Pyx_PyUnicode_GET_LENGTH", + Builtin.bytes_type: "PyBytes_GET_SIZE", Builtin.bytearray_type: 'PyByteArray_GET_SIZE', - Builtin.list_type: "PyList_GET_SIZE", - Builtin.tuple_type: "PyTuple_GET_SIZE", - Builtin.set_type: "PySet_GET_SIZE", - Builtin.frozenset_type: "PySet_GET_SIZE", - Builtin.dict_type: "PyDict_Size", - }.get + Builtin.list_type: "PyList_GET_SIZE", + Builtin.tuple_type: "PyTuple_GET_SIZE", + Builtin.set_type: "PySet_GET_SIZE", + Builtin.frozenset_type: "PySet_GET_SIZE", + Builtin.dict_type: "PyDict_Size", + }.get _ext_types_with_pysize = set(["cpython.array.array"]) @@ -2668,14 +2668,14 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, if len(pos_args) != 2: return node arg, types = pos_args - temps = [] + temps = [] if isinstance(types, ExprNodes.TupleNode): types = types.args - if len(types) == 1 and not types[0].type is Builtin.type_type: - return node # nothing to improve here + if len(types) == 1 and not types[0].type is Builtin.type_type: + return node # nothing to improve here if arg.is_attribute or not arg.is_simple(): - arg = UtilNodes.ResultRefNode(arg) - temps.append(arg) + arg = UtilNodes.ResultRefNode(arg) + temps.append(arg) elif types.type is Builtin.type_type: types = [types] else: @@ -2706,17 +2706,17 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, type_check_function = '__Pyx_TypeCheck' type_check_args = [arg, test_type_node] else: - if not test_type_node.is_literal: - test_type_node = UtilNodes.ResultRefNode(test_type_node) - temps.append(test_type_node) - type_check_function = 'PyObject_IsInstance' - type_check_args = [arg, test_type_node] + if not test_type_node.is_literal: + test_type_node = UtilNodes.ResultRefNode(test_type_node) + temps.append(test_type_node) + type_check_function = 'PyObject_IsInstance' + type_check_args = [arg, test_type_node] test_nodes.append( ExprNodes.PythonCapiCallNode( test_type_node.pos, type_check_function, self.Py_type_check_func_type, - args=type_check_args, - is_temp=True, - )) + args=type_check_args, + is_temp=True, + )) def join_with_or(a, b, make_binop_node=ExprNodes.binop_node): or_node = make_binop_node(node.pos, 'or', a, b) @@ -2725,7 +2725,7 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, return or_node test_node = reduce(join_with_or, test_nodes).coerce_to(node.type, env) - for temp in temps[::-1]: + for temp in temps[::-1]: test_node = UtilNodes.EvalWithTempExprNode(temp, test_node) return test_node @@ -2738,7 +2738,7 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, if isinstance(arg, ExprNodes.CoerceToPyTypeNode): if arg.arg.type.is_unicode_char: return ExprNodes.TypecastNode( - arg.pos, operand=arg.arg, type=PyrexTypes.c_long_type + arg.pos, operand=arg.arg, type=PyrexTypes.c_long_type ).coerce_to(node.type, self.current_env()) elif isinstance(arg, ExprNodes.UnicodeNode): if len(arg.value) == 1: @@ -2990,8 +2990,8 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, PyObject_PopIndex_func_type = PyrexTypes.CFuncType( PyrexTypes.py_object_type, [ PyrexTypes.CFuncTypeArg("list", PyrexTypes.py_object_type, None), - PyrexTypes.CFuncTypeArg("py_index", PyrexTypes.py_object_type, None), - PyrexTypes.CFuncTypeArg("c_index", PyrexTypes.c_py_ssize_t_type, None), + PyrexTypes.CFuncTypeArg("py_index", PyrexTypes.py_object_type, None), + PyrexTypes.CFuncTypeArg("c_index", PyrexTypes.c_py_ssize_t_type, None), PyrexTypes.CFuncTypeArg("is_signed", PyrexTypes.c_int_type, None), ], has_varargs=True) # to fake the additional macro args that lack a proper C type @@ -3026,23 +3026,23 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, ) elif len(args) == 2: index = unwrap_coerced_node(args[1]) - py_index = ExprNodes.NoneNode(index.pos) + py_index = ExprNodes.NoneNode(index.pos) orig_index_type = index.type if not index.type.is_int: - if isinstance(index, ExprNodes.IntNode): - py_index = index.coerce_to_pyobject(self.current_env()) + if isinstance(index, ExprNodes.IntNode): + py_index = index.coerce_to_pyobject(self.current_env()) + index = index.coerce_to(PyrexTypes.c_py_ssize_t_type, self.current_env()) + elif is_list: + if index.type.is_pyobject: + py_index = index.coerce_to_simple(self.current_env()) + index = ExprNodes.CloneNode(py_index) index = index.coerce_to(PyrexTypes.c_py_ssize_t_type, self.current_env()) - elif is_list: - if index.type.is_pyobject: - py_index = index.coerce_to_simple(self.current_env()) - index = ExprNodes.CloneNode(py_index) - index = index.coerce_to(PyrexTypes.c_py_ssize_t_type, self.current_env()) else: return node elif not PyrexTypes.numeric_type_fits(index.type, PyrexTypes.c_py_ssize_t_type): return node - elif isinstance(index, ExprNodes.IntNode): - py_index = index.coerce_to_pyobject(self.current_env()) + elif isinstance(index, ExprNodes.IntNode): + py_index = index.coerce_to_pyobject(self.current_env()) # real type might still be larger at runtime if not orig_index_type.is_int: orig_index_type = index.type @@ -3054,12 +3054,12 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, return ExprNodes.PythonCapiCallNode( node.pos, "__Pyx_Py%s_PopIndex" % type_name, self.PyObject_PopIndex_func_type, - args=[obj, py_index, index, + args=[obj, py_index, index, ExprNodes.IntNode(index.pos, value=str(orig_index_type.signed and 1 or 0), constant_result=orig_index_type.signed and 1 or 0, type=PyrexTypes.c_int_type), ExprNodes.RawCNameExprNode(index.pos, PyrexTypes.c_void_type, - orig_index_type.empty_declaration_code()), + orig_index_type.empty_declaration_code()), ExprNodes.RawCNameExprNode(index.pos, conversion_type, convert_func)], may_return_none=True, is_temp=node.is_temp, @@ -3163,184 +3163,184 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, may_return_none=True, utility_code=load_c_utility('py_dict_pop')) - Pyx_BinopInt_func_types = dict( - ((ctype, ret_type), PyrexTypes.CFuncType( - ret_type, [ - PyrexTypes.CFuncTypeArg("op1", PyrexTypes.py_object_type, None), - PyrexTypes.CFuncTypeArg("op2", PyrexTypes.py_object_type, None), - PyrexTypes.CFuncTypeArg("cval", ctype, None), - PyrexTypes.CFuncTypeArg("inplace", PyrexTypes.c_bint_type, None), - PyrexTypes.CFuncTypeArg("zerodiv_check", PyrexTypes.c_bint_type, None), - ], exception_value=None if ret_type.is_pyobject else ret_type.exception_value)) - for ctype in (PyrexTypes.c_long_type, PyrexTypes.c_double_type) - for ret_type in (PyrexTypes.py_object_type, PyrexTypes.c_bint_type) - ) - - def _handle_simple_method_object___add__(self, node, function, args, is_unbound_method): - return self._optimise_num_binop('Add', node, function, args, is_unbound_method) - - def _handle_simple_method_object___sub__(self, node, function, args, is_unbound_method): - return self._optimise_num_binop('Subtract', node, function, args, is_unbound_method) - - def _handle_simple_method_object___eq__(self, node, function, args, is_unbound_method): - return self._optimise_num_binop('Eq', node, function, args, is_unbound_method) - - def _handle_simple_method_object___ne__(self, node, function, args, is_unbound_method): - return self._optimise_num_binop('Ne', node, function, args, is_unbound_method) - - def _handle_simple_method_object___and__(self, node, function, args, is_unbound_method): - return self._optimise_num_binop('And', node, function, args, is_unbound_method) - - def _handle_simple_method_object___or__(self, node, function, args, is_unbound_method): - return self._optimise_num_binop('Or', node, function, args, is_unbound_method) - - def _handle_simple_method_object___xor__(self, node, function, args, is_unbound_method): - return self._optimise_num_binop('Xor', node, function, args, is_unbound_method) - - def _handle_simple_method_object___rshift__(self, node, function, args, is_unbound_method): - if len(args) != 2 or not isinstance(args[1], ExprNodes.IntNode): - return node - if not args[1].has_constant_result() or not (1 <= args[1].constant_result <= 63): - return node - return self._optimise_num_binop('Rshift', node, function, args, is_unbound_method) - - def _handle_simple_method_object___lshift__(self, node, function, args, is_unbound_method): - if len(args) != 2 or not isinstance(args[1], ExprNodes.IntNode): - return node - if not args[1].has_constant_result() or not (1 <= args[1].constant_result <= 63): - return node - return self._optimise_num_binop('Lshift', node, function, args, is_unbound_method) - - def _handle_simple_method_object___mod__(self, node, function, args, is_unbound_method): - return self._optimise_num_div('Remainder', node, function, args, is_unbound_method) - - def _handle_simple_method_object___floordiv__(self, node, function, args, is_unbound_method): - return self._optimise_num_div('FloorDivide', node, function, args, is_unbound_method) - - def _handle_simple_method_object___truediv__(self, node, function, args, is_unbound_method): - return self._optimise_num_div('TrueDivide', node, function, args, is_unbound_method) - - def _handle_simple_method_object___div__(self, node, function, args, is_unbound_method): - return self._optimise_num_div('Divide', node, function, args, is_unbound_method) - - def _optimise_num_div(self, operator, node, function, args, is_unbound_method): - if len(args) != 2 or not args[1].has_constant_result() or args[1].constant_result == 0: - return node - if isinstance(args[1], ExprNodes.IntNode): - if not (-2**30 <= args[1].constant_result <= 2**30): - return node - elif isinstance(args[1], ExprNodes.FloatNode): - if not (-2**53 <= args[1].constant_result <= 2**53): - return node - else: - return node - return self._optimise_num_binop(operator, node, function, args, is_unbound_method) - - def _handle_simple_method_float___add__(self, node, function, args, is_unbound_method): - return self._optimise_num_binop('Add', node, function, args, is_unbound_method) - - def _handle_simple_method_float___sub__(self, node, function, args, is_unbound_method): - return self._optimise_num_binop('Subtract', node, function, args, is_unbound_method) - - def _handle_simple_method_float___truediv__(self, node, function, args, is_unbound_method): - return self._optimise_num_binop('TrueDivide', node, function, args, is_unbound_method) - - def _handle_simple_method_float___div__(self, node, function, args, is_unbound_method): - return self._optimise_num_binop('Divide', node, function, args, is_unbound_method) - - def _handle_simple_method_float___mod__(self, node, function, args, is_unbound_method): - return self._optimise_num_binop('Remainder', node, function, args, is_unbound_method) - - def _handle_simple_method_float___eq__(self, node, function, args, is_unbound_method): - return self._optimise_num_binop('Eq', node, function, args, is_unbound_method) - - def _handle_simple_method_float___ne__(self, node, function, args, is_unbound_method): - return self._optimise_num_binop('Ne', node, function, args, is_unbound_method) - - def _optimise_num_binop(self, operator, node, function, args, is_unbound_method): - """ - Optimise math operators for (likely) float or small integer operations. - """ - if len(args) != 2: - return node - - if node.type.is_pyobject: - ret_type = PyrexTypes.py_object_type - elif node.type is PyrexTypes.c_bint_type and operator in ('Eq', 'Ne'): - ret_type = PyrexTypes.c_bint_type - else: - return node - - # When adding IntNode/FloatNode to something else, assume other operand is also numeric. - # Prefer constants on RHS as they allows better size control for some operators. - num_nodes = (ExprNodes.IntNode, ExprNodes.FloatNode) - if isinstance(args[1], num_nodes): - if args[0].type is not PyrexTypes.py_object_type: - return node - numval = args[1] - arg_order = 'ObjC' - elif isinstance(args[0], num_nodes): - if args[1].type is not PyrexTypes.py_object_type: - return node - numval = args[0] - arg_order = 'CObj' - else: - return node - - if not numval.has_constant_result(): - return node - - is_float = isinstance(numval, ExprNodes.FloatNode) - num_type = PyrexTypes.c_double_type if is_float else PyrexTypes.c_long_type - if is_float: - if operator not in ('Add', 'Subtract', 'Remainder', 'TrueDivide', 'Divide', 'Eq', 'Ne'): - return node - elif operator == 'Divide': - # mixed old-/new-style division is not currently optimised for integers - return node - elif abs(numval.constant_result) > 2**30: - # Cut off at an integer border that is still safe for all operations. - return node - - if operator in ('TrueDivide', 'FloorDivide', 'Divide', 'Remainder'): - if args[1].constant_result == 0: - # Don't optimise division by 0. :) - return node - - args = list(args) - args.append((ExprNodes.FloatNode if is_float else ExprNodes.IntNode)( - numval.pos, value=numval.value, constant_result=numval.constant_result, - type=num_type)) - inplace = node.inplace if isinstance(node, ExprNodes.NumBinopNode) else False - args.append(ExprNodes.BoolNode(node.pos, value=inplace, constant_result=inplace)) - if is_float or operator not in ('Eq', 'Ne'): - # "PyFloatBinop" and "PyIntBinop" take an additional "check for zero division" argument. - zerodivision_check = arg_order == 'CObj' and ( - not node.cdivision if isinstance(node, ExprNodes.DivNode) else False) - args.append(ExprNodes.BoolNode(node.pos, value=zerodivision_check, constant_result=zerodivision_check)) - - utility_code = TempitaUtilityCode.load_cached( - "PyFloatBinop" if is_float else "PyIntCompare" if operator in ('Eq', 'Ne') else "PyIntBinop", - "Optimize.c", - context=dict(op=operator, order=arg_order, ret_type=ret_type)) - - call_node = self._substitute_method_call( - node, function, - "__Pyx_Py%s_%s%s%s" % ( - 'Float' if is_float else 'Int', - '' if ret_type.is_pyobject else 'Bool', - operator, - arg_order), - self.Pyx_BinopInt_func_types[(num_type, ret_type)], - '__%s__' % operator[:3].lower(), is_unbound_method, args, - may_return_none=True, - with_none_check=False, - utility_code=utility_code) - - if node.type.is_pyobject and not ret_type.is_pyobject: - call_node = ExprNodes.CoerceToPyTypeNode(call_node, self.current_env(), node.type) - return call_node - + Pyx_BinopInt_func_types = dict( + ((ctype, ret_type), PyrexTypes.CFuncType( + ret_type, [ + PyrexTypes.CFuncTypeArg("op1", PyrexTypes.py_object_type, None), + PyrexTypes.CFuncTypeArg("op2", PyrexTypes.py_object_type, None), + PyrexTypes.CFuncTypeArg("cval", ctype, None), + PyrexTypes.CFuncTypeArg("inplace", PyrexTypes.c_bint_type, None), + PyrexTypes.CFuncTypeArg("zerodiv_check", PyrexTypes.c_bint_type, None), + ], exception_value=None if ret_type.is_pyobject else ret_type.exception_value)) + for ctype in (PyrexTypes.c_long_type, PyrexTypes.c_double_type) + for ret_type in (PyrexTypes.py_object_type, PyrexTypes.c_bint_type) + ) + + def _handle_simple_method_object___add__(self, node, function, args, is_unbound_method): + return self._optimise_num_binop('Add', node, function, args, is_unbound_method) + + def _handle_simple_method_object___sub__(self, node, function, args, is_unbound_method): + return self._optimise_num_binop('Subtract', node, function, args, is_unbound_method) + + def _handle_simple_method_object___eq__(self, node, function, args, is_unbound_method): + return self._optimise_num_binop('Eq', node, function, args, is_unbound_method) + + def _handle_simple_method_object___ne__(self, node, function, args, is_unbound_method): + return self._optimise_num_binop('Ne', node, function, args, is_unbound_method) + + def _handle_simple_method_object___and__(self, node, function, args, is_unbound_method): + return self._optimise_num_binop('And', node, function, args, is_unbound_method) + + def _handle_simple_method_object___or__(self, node, function, args, is_unbound_method): + return self._optimise_num_binop('Or', node, function, args, is_unbound_method) + + def _handle_simple_method_object___xor__(self, node, function, args, is_unbound_method): + return self._optimise_num_binop('Xor', node, function, args, is_unbound_method) + + def _handle_simple_method_object___rshift__(self, node, function, args, is_unbound_method): + if len(args) != 2 or not isinstance(args[1], ExprNodes.IntNode): + return node + if not args[1].has_constant_result() or not (1 <= args[1].constant_result <= 63): + return node + return self._optimise_num_binop('Rshift', node, function, args, is_unbound_method) + + def _handle_simple_method_object___lshift__(self, node, function, args, is_unbound_method): + if len(args) != 2 or not isinstance(args[1], ExprNodes.IntNode): + return node + if not args[1].has_constant_result() or not (1 <= args[1].constant_result <= 63): + return node + return self._optimise_num_binop('Lshift', node, function, args, is_unbound_method) + + def _handle_simple_method_object___mod__(self, node, function, args, is_unbound_method): + return self._optimise_num_div('Remainder', node, function, args, is_unbound_method) + + def _handle_simple_method_object___floordiv__(self, node, function, args, is_unbound_method): + return self._optimise_num_div('FloorDivide', node, function, args, is_unbound_method) + + def _handle_simple_method_object___truediv__(self, node, function, args, is_unbound_method): + return self._optimise_num_div('TrueDivide', node, function, args, is_unbound_method) + + def _handle_simple_method_object___div__(self, node, function, args, is_unbound_method): + return self._optimise_num_div('Divide', node, function, args, is_unbound_method) + + def _optimise_num_div(self, operator, node, function, args, is_unbound_method): + if len(args) != 2 or not args[1].has_constant_result() or args[1].constant_result == 0: + return node + if isinstance(args[1], ExprNodes.IntNode): + if not (-2**30 <= args[1].constant_result <= 2**30): + return node + elif isinstance(args[1], ExprNodes.FloatNode): + if not (-2**53 <= args[1].constant_result <= 2**53): + return node + else: + return node + return self._optimise_num_binop(operator, node, function, args, is_unbound_method) + + def _handle_simple_method_float___add__(self, node, function, args, is_unbound_method): + return self._optimise_num_binop('Add', node, function, args, is_unbound_method) + + def _handle_simple_method_float___sub__(self, node, function, args, is_unbound_method): + return self._optimise_num_binop('Subtract', node, function, args, is_unbound_method) + + def _handle_simple_method_float___truediv__(self, node, function, args, is_unbound_method): + return self._optimise_num_binop('TrueDivide', node, function, args, is_unbound_method) + + def _handle_simple_method_float___div__(self, node, function, args, is_unbound_method): + return self._optimise_num_binop('Divide', node, function, args, is_unbound_method) + + def _handle_simple_method_float___mod__(self, node, function, args, is_unbound_method): + return self._optimise_num_binop('Remainder', node, function, args, is_unbound_method) + + def _handle_simple_method_float___eq__(self, node, function, args, is_unbound_method): + return self._optimise_num_binop('Eq', node, function, args, is_unbound_method) + + def _handle_simple_method_float___ne__(self, node, function, args, is_unbound_method): + return self._optimise_num_binop('Ne', node, function, args, is_unbound_method) + + def _optimise_num_binop(self, operator, node, function, args, is_unbound_method): + """ + Optimise math operators for (likely) float or small integer operations. + """ + if len(args) != 2: + return node + + if node.type.is_pyobject: + ret_type = PyrexTypes.py_object_type + elif node.type is PyrexTypes.c_bint_type and operator in ('Eq', 'Ne'): + ret_type = PyrexTypes.c_bint_type + else: + return node + + # When adding IntNode/FloatNode to something else, assume other operand is also numeric. + # Prefer constants on RHS as they allows better size control for some operators. + num_nodes = (ExprNodes.IntNode, ExprNodes.FloatNode) + if isinstance(args[1], num_nodes): + if args[0].type is not PyrexTypes.py_object_type: + return node + numval = args[1] + arg_order = 'ObjC' + elif isinstance(args[0], num_nodes): + if args[1].type is not PyrexTypes.py_object_type: + return node + numval = args[0] + arg_order = 'CObj' + else: + return node + + if not numval.has_constant_result(): + return node + + is_float = isinstance(numval, ExprNodes.FloatNode) + num_type = PyrexTypes.c_double_type if is_float else PyrexTypes.c_long_type + if is_float: + if operator not in ('Add', 'Subtract', 'Remainder', 'TrueDivide', 'Divide', 'Eq', 'Ne'): + return node + elif operator == 'Divide': + # mixed old-/new-style division is not currently optimised for integers + return node + elif abs(numval.constant_result) > 2**30: + # Cut off at an integer border that is still safe for all operations. + return node + + if operator in ('TrueDivide', 'FloorDivide', 'Divide', 'Remainder'): + if args[1].constant_result == 0: + # Don't optimise division by 0. :) + return node + + args = list(args) + args.append((ExprNodes.FloatNode if is_float else ExprNodes.IntNode)( + numval.pos, value=numval.value, constant_result=numval.constant_result, + type=num_type)) + inplace = node.inplace if isinstance(node, ExprNodes.NumBinopNode) else False + args.append(ExprNodes.BoolNode(node.pos, value=inplace, constant_result=inplace)) + if is_float or operator not in ('Eq', 'Ne'): + # "PyFloatBinop" and "PyIntBinop" take an additional "check for zero division" argument. + zerodivision_check = arg_order == 'CObj' and ( + not node.cdivision if isinstance(node, ExprNodes.DivNode) else False) + args.append(ExprNodes.BoolNode(node.pos, value=zerodivision_check, constant_result=zerodivision_check)) + + utility_code = TempitaUtilityCode.load_cached( + "PyFloatBinop" if is_float else "PyIntCompare" if operator in ('Eq', 'Ne') else "PyIntBinop", + "Optimize.c", + context=dict(op=operator, order=arg_order, ret_type=ret_type)) + + call_node = self._substitute_method_call( + node, function, + "__Pyx_Py%s_%s%s%s" % ( + 'Float' if is_float else 'Int', + '' if ret_type.is_pyobject else 'Bool', + operator, + arg_order), + self.Pyx_BinopInt_func_types[(num_type, ret_type)], + '__%s__' % operator[:3].lower(), is_unbound_method, args, + may_return_none=True, + with_none_check=False, + utility_code=utility_code) + + if node.type.is_pyobject and not ret_type.is_pyobject: + call_node = ExprNodes.CoerceToPyTypeNode(call_node, self.current_env(), node.type) + return call_node + ### unicode type methods PyUnicode_uchar_predicate_func_type = PyrexTypes.CFuncType( @@ -3456,44 +3456,44 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, "PyUnicode_Split", self.PyUnicode_Split_func_type, 'split', is_unbound_method, args) - PyUnicode_Join_func_type = PyrexTypes.CFuncType( - Builtin.unicode_type, [ - PyrexTypes.CFuncTypeArg("str", Builtin.unicode_type, None), - PyrexTypes.CFuncTypeArg("seq", PyrexTypes.py_object_type, None), - ]) - - def _handle_simple_method_unicode_join(self, node, function, args, is_unbound_method): - """ - unicode.join() builds a list first => see if we can do this more efficiently - """ - if len(args) != 2: - self._error_wrong_arg_count('unicode.join', node, args, "2") - return node - if isinstance(args[1], ExprNodes.GeneratorExpressionNode): - gen_expr_node = args[1] - loop_node = gen_expr_node.loop - - yield_statements = _find_yield_statements(loop_node) - if yield_statements: - inlined_genexpr = ExprNodes.InlinedGeneratorExpressionNode( - node.pos, gen_expr_node, orig_func='list', - comprehension_type=Builtin.list_type) - - for yield_expression, yield_stat_node in yield_statements: - append_node = ExprNodes.ComprehensionAppendNode( - yield_expression.pos, - expr=yield_expression, - target=inlined_genexpr.target) - - Visitor.recursively_replace_node(gen_expr_node, yield_stat_node, append_node) - - args[1] = inlined_genexpr - - return self._substitute_method_call( - node, function, - "PyUnicode_Join", self.PyUnicode_Join_func_type, - 'join', is_unbound_method, args) - + PyUnicode_Join_func_type = PyrexTypes.CFuncType( + Builtin.unicode_type, [ + PyrexTypes.CFuncTypeArg("str", Builtin.unicode_type, None), + PyrexTypes.CFuncTypeArg("seq", PyrexTypes.py_object_type, None), + ]) + + def _handle_simple_method_unicode_join(self, node, function, args, is_unbound_method): + """ + unicode.join() builds a list first => see if we can do this more efficiently + """ + if len(args) != 2: + self._error_wrong_arg_count('unicode.join', node, args, "2") + return node + if isinstance(args[1], ExprNodes.GeneratorExpressionNode): + gen_expr_node = args[1] + loop_node = gen_expr_node.loop + + yield_statements = _find_yield_statements(loop_node) + if yield_statements: + inlined_genexpr = ExprNodes.InlinedGeneratorExpressionNode( + node.pos, gen_expr_node, orig_func='list', + comprehension_type=Builtin.list_type) + + for yield_expression, yield_stat_node in yield_statements: + append_node = ExprNodes.ComprehensionAppendNode( + yield_expression.pos, + expr=yield_expression, + target=inlined_genexpr.target) + + Visitor.recursively_replace_node(gen_expr_node, yield_stat_node, append_node) + + args[1] = inlined_genexpr + + return self._substitute_method_call( + node, function, + "PyUnicode_Join", self.PyUnicode_Join_func_type, + 'join', is_unbound_method, args) + PyString_Tailmatch_func_type = PyrexTypes.CFuncType( PyrexTypes.c_bint_type, [ PyrexTypes.CFuncTypeArg("str", PyrexTypes.py_object_type, None), # bytes/str/unicode @@ -3626,8 +3626,8 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, PyUnicode_AsEncodedString_func_type = PyrexTypes.CFuncType( Builtin.bytes_type, [ PyrexTypes.CFuncTypeArg("obj", Builtin.unicode_type, None), - PyrexTypes.CFuncTypeArg("encoding", PyrexTypes.c_const_char_ptr_type, None), - PyrexTypes.CFuncTypeArg("errors", PyrexTypes.c_const_char_ptr_type, None), + PyrexTypes.CFuncTypeArg("encoding", PyrexTypes.c_const_char_ptr_type, None), + PyrexTypes.CFuncTypeArg("errors", PyrexTypes.c_const_char_ptr_type, None), ]) PyUnicode_AsXyzString_func_type = PyrexTypes.CFuncType( @@ -3671,8 +3671,8 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, # well, looks like we can't pass else: - value = bytes_literal(value, encoding) - return ExprNodes.BytesNode(string_node.pos, value=value, type=Builtin.bytes_type) + value = bytes_literal(value, encoding) + return ExprNodes.BytesNode(string_node.pos, value=value, type=Builtin.bytes_type) if encoding and error_handling == 'strict': # try to find a specific encoder function @@ -3692,30 +3692,30 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, PyUnicode_DecodeXyz_func_ptr_type = PyrexTypes.CPtrType(PyrexTypes.CFuncType( Builtin.unicode_type, [ - PyrexTypes.CFuncTypeArg("string", PyrexTypes.c_const_char_ptr_type, None), + PyrexTypes.CFuncTypeArg("string", PyrexTypes.c_const_char_ptr_type, None), PyrexTypes.CFuncTypeArg("size", PyrexTypes.c_py_ssize_t_type, None), - PyrexTypes.CFuncTypeArg("errors", PyrexTypes.c_const_char_ptr_type, None), - ])) + PyrexTypes.CFuncTypeArg("errors", PyrexTypes.c_const_char_ptr_type, None), + ])) _decode_c_string_func_type = PyrexTypes.CFuncType( Builtin.unicode_type, [ - PyrexTypes.CFuncTypeArg("string", PyrexTypes.c_const_char_ptr_type, None), + PyrexTypes.CFuncTypeArg("string", PyrexTypes.c_const_char_ptr_type, None), PyrexTypes.CFuncTypeArg("start", PyrexTypes.c_py_ssize_t_type, None), PyrexTypes.CFuncTypeArg("stop", PyrexTypes.c_py_ssize_t_type, None), - PyrexTypes.CFuncTypeArg("encoding", PyrexTypes.c_const_char_ptr_type, None), - PyrexTypes.CFuncTypeArg("errors", PyrexTypes.c_const_char_ptr_type, None), + PyrexTypes.CFuncTypeArg("encoding", PyrexTypes.c_const_char_ptr_type, None), + PyrexTypes.CFuncTypeArg("errors", PyrexTypes.c_const_char_ptr_type, None), PyrexTypes.CFuncTypeArg("decode_func", PyUnicode_DecodeXyz_func_ptr_type, None), - ]) + ]) _decode_bytes_func_type = PyrexTypes.CFuncType( Builtin.unicode_type, [ PyrexTypes.CFuncTypeArg("string", PyrexTypes.py_object_type, None), PyrexTypes.CFuncTypeArg("start", PyrexTypes.c_py_ssize_t_type, None), PyrexTypes.CFuncTypeArg("stop", PyrexTypes.c_py_ssize_t_type, None), - PyrexTypes.CFuncTypeArg("encoding", PyrexTypes.c_const_char_ptr_type, None), - PyrexTypes.CFuncTypeArg("errors", PyrexTypes.c_const_char_ptr_type, None), + PyrexTypes.CFuncTypeArg("encoding", PyrexTypes.c_const_char_ptr_type, None), + PyrexTypes.CFuncTypeArg("errors", PyrexTypes.c_const_char_ptr_type, None), PyrexTypes.CFuncTypeArg("decode_func", PyUnicode_DecodeXyz_func_ptr_type, None), - ]) + ]) _decode_cpp_string_func_type = None # lazy init @@ -3810,8 +3810,8 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, PyrexTypes.CFuncTypeArg("string", string_type, None), PyrexTypes.CFuncTypeArg("start", PyrexTypes.c_py_ssize_t_type, None), PyrexTypes.CFuncTypeArg("stop", PyrexTypes.c_py_ssize_t_type, None), - PyrexTypes.CFuncTypeArg("encoding", PyrexTypes.c_const_char_ptr_type, None), - PyrexTypes.CFuncTypeArg("errors", PyrexTypes.c_const_char_ptr_type, None), + PyrexTypes.CFuncTypeArg("encoding", PyrexTypes.c_const_char_ptr_type, None), + PyrexTypes.CFuncTypeArg("errors", PyrexTypes.c_const_char_ptr_type, None), PyrexTypes.CFuncTypeArg("decode_func", self.PyUnicode_DecodeXyz_func_ptr_type, None), ]) helper_func_type = self._decode_cpp_string_func_type @@ -3882,14 +3882,14 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, if isinstance(node, ExprNodes.UnicodeNode): encoding = node.value node = ExprNodes.BytesNode( - node.pos, value=encoding.as_utf8_string(), type=PyrexTypes.c_const_char_ptr_type) + node.pos, value=encoding.as_utf8_string(), type=PyrexTypes.c_const_char_ptr_type) elif isinstance(node, (ExprNodes.StringNode, ExprNodes.BytesNode)): encoding = node.value.decode('ISO-8859-1') node = ExprNodes.BytesNode( - node.pos, value=node.value, type=PyrexTypes.c_const_char_ptr_type) + node.pos, value=node.value, type=PyrexTypes.c_const_char_ptr_type) elif node.type is Builtin.bytes_type: encoding = None - node = node.coerce_to(PyrexTypes.c_const_char_ptr_type, self.current_env()) + node = node.coerce_to(PyrexTypes.c_const_char_ptr_type, self.current_env()) elif node.type.is_string: encoding = None else: @@ -3933,8 +3933,8 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, def _substitute_method_call(self, node, function, name, func_type, attr_name, is_unbound_method, args=(), utility_code=None, is_temp=None, - may_return_none=ExprNodes.PythonCapiCallNode.may_return_none, - with_none_check=True): + may_return_none=ExprNodes.PythonCapiCallNode.may_return_none, + with_none_check=True): args = list(args) if with_none_check and args: args[0] = self._wrap_self_arg(args[0], function, is_unbound_method, attr_name) @@ -4210,15 +4210,15 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations): bytes_value = None if str1.bytes_value is not None and str2.bytes_value is not None: if str1.bytes_value.encoding == str2.bytes_value.encoding: - bytes_value = bytes_literal( - str1.bytes_value + str2.bytes_value, - str1.bytes_value.encoding) + bytes_value = bytes_literal( + str1.bytes_value + str2.bytes_value, + str1.bytes_value.encoding) string_value = EncodedString(node.constant_result) return ExprNodes.UnicodeNode( str1.pos, value=string_value, constant_result=node.constant_result, bytes_value=bytes_value) elif isinstance(str1, ExprNodes.BytesNode) and isinstance(str2, ExprNodes.BytesNode): if str1.value.encoding == str2.value.encoding: - bytes_value = bytes_literal(node.constant_result, str1.value.encoding) + bytes_value = bytes_literal(node.constant_result, str1.value.encoding) return ExprNodes.BytesNode(str1.pos, value=bytes_value, constant_result=node.constant_result) # all other combinations are rather complicated # to get right in Py2/3: encodings, unicode escapes, ... @@ -4275,12 +4275,12 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations): def _calculate_constant_seq(self, node, sequence_node, factor): if factor.constant_result != 1 and sequence_node.args: - if isinstance(factor.constant_result, _py_int_types) and factor.constant_result <= 0: + if isinstance(factor.constant_result, _py_int_types) and factor.constant_result <= 0: del sequence_node.args[:] sequence_node.mult_factor = None elif sequence_node.mult_factor is not None: - if (isinstance(factor.constant_result, _py_int_types) and - isinstance(sequence_node.mult_factor.constant_result, _py_int_types)): + if (isinstance(factor.constant_result, _py_int_types) and + isinstance(sequence_node.mult_factor.constant_result, _py_int_types)): value = sequence_node.mult_factor.constant_result * factor.constant_result sequence_node.mult_factor = ExprNodes.IntNode( sequence_node.mult_factor.pos, @@ -4332,16 +4332,16 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations): warning(pos, "Too few arguments for format placeholders", level=1) can_be_optimised = False break - if arg.is_starred: - can_be_optimised = False - break - if format_type in u'asrfdoxX': + if arg.is_starred: + can_be_optimised = False + break + if format_type in u'asrfdoxX': format_spec = s[1:] conversion_char = None if format_type in u'doxX' and u'.' in format_spec: # Precision is not allowed for integers in format(), but ok in %-formatting. can_be_optimised = False - elif format_type in u'ars': + elif format_type in u'ars': format_spec = format_spec[:-1] conversion_char = format_type if format_spec.startswith('0'): @@ -4363,7 +4363,7 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations): else: # keep it simple for now ... can_be_optimised = False - break + break if not can_be_optimised: # Print all warnings we can find before finally giving up here. @@ -4379,11 +4379,11 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations): node = ExprNodes.JoinedStrNode(pos, values=substrings) return self.visit_JoinedStrNode(node) - def visit_FormattedValueNode(self, node): - self.visitchildren(node) + def visit_FormattedValueNode(self, node): + self.visitchildren(node) conversion_char = node.conversion_char or 's' - if isinstance(node.format_spec, ExprNodes.UnicodeNode) and not node.format_spec.value: - node.format_spec = None + if isinstance(node.format_spec, ExprNodes.UnicodeNode) and not node.format_spec.value: + node.format_spec = None if node.format_spec is None and isinstance(node.value, ExprNodes.IntNode): value = EncodedString(node.value.value) if value.isdigit(): @@ -4396,130 +4396,130 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations): value = node.value.unicode_value if value is not None: return ExprNodes.UnicodeNode(node.value.pos, value=value, constant_result=value) - return node - - def visit_JoinedStrNode(self, node): - """ - Clean up after the parser by discarding empty Unicode strings and merging - substring sequences. Empty or single-value join lists are not uncommon - because f-string format specs are always parsed into JoinedStrNodes. - """ - self.visitchildren(node) - unicode_node = ExprNodes.UnicodeNode - - values = [] - for is_unode_group, substrings in itertools.groupby(node.values, lambda v: isinstance(v, unicode_node)): - if is_unode_group: - substrings = list(substrings) - unode = substrings[0] - if len(substrings) > 1: + return node + + def visit_JoinedStrNode(self, node): + """ + Clean up after the parser by discarding empty Unicode strings and merging + substring sequences. Empty or single-value join lists are not uncommon + because f-string format specs are always parsed into JoinedStrNodes. + """ + self.visitchildren(node) + unicode_node = ExprNodes.UnicodeNode + + values = [] + for is_unode_group, substrings in itertools.groupby(node.values, lambda v: isinstance(v, unicode_node)): + if is_unode_group: + substrings = list(substrings) + unode = substrings[0] + if len(substrings) > 1: value = EncodedString(u''.join(value.value for value in substrings)) unode = ExprNodes.UnicodeNode(unode.pos, value=value, constant_result=value) - # ignore empty Unicode strings - if unode.value: - values.append(unode) - else: - values.extend(substrings) - - if not values: + # ignore empty Unicode strings + if unode.value: + values.append(unode) + else: + values.extend(substrings) + + if not values: value = EncodedString('') node = ExprNodes.UnicodeNode(node.pos, value=value, constant_result=value) - elif len(values) == 1: - node = values[0] - elif len(values) == 2: - # reduce to string concatenation - node = ExprNodes.binop_node(node.pos, '+', *values) - else: - node.values = values - return node - - def visit_MergedDictNode(self, node): - """Unpack **args in place if we can.""" - self.visitchildren(node) - args = [] - items = [] - - def add(arg): - if arg.is_dict_literal: - if items: - items[0].key_value_pairs.extend(arg.key_value_pairs) - else: - items.append(arg) - elif isinstance(arg, ExprNodes.MergedDictNode): - for child_arg in arg.keyword_args: - add(child_arg) - else: - if items: - args.append(items[0]) - del items[:] - args.append(arg) - - for arg in node.keyword_args: - add(arg) - if items: - args.append(items[0]) - - if len(args) == 1: - arg = args[0] - if arg.is_dict_literal or isinstance(arg, ExprNodes.MergedDictNode): - return arg - node.keyword_args[:] = args - self._calculate_const(node) - return node - - def visit_MergedSequenceNode(self, node): - """Unpack *args in place if we can.""" - self.visitchildren(node) - - is_set = node.type is Builtin.set_type - args = [] - values = [] - - def add(arg): - if (is_set and arg.is_set_literal) or (arg.is_sequence_constructor and not arg.mult_factor): - if values: - values[0].args.extend(arg.args) - else: - values.append(arg) - elif isinstance(arg, ExprNodes.MergedSequenceNode): - for child_arg in arg.args: - add(child_arg) - else: - if values: - args.append(values[0]) - del values[:] - args.append(arg) - - for arg in node.args: - add(arg) - if values: - args.append(values[0]) - - if len(args) == 1: - arg = args[0] - if ((is_set and arg.is_set_literal) or - (arg.is_sequence_constructor and arg.type is node.type) or - isinstance(arg, ExprNodes.MergedSequenceNode)): - return arg - node.args[:] = args - self._calculate_const(node) - return node - - def visit_SequenceNode(self, node): - """Unpack *args in place if we can.""" - self.visitchildren(node) - args = [] - for arg in node.args: - if not arg.is_starred: - args.append(arg) - elif arg.target.is_sequence_constructor and not arg.target.mult_factor: - args.extend(arg.target.args) - else: - args.append(arg) - node.args[:] = args - self._calculate_const(node) - return node - + elif len(values) == 1: + node = values[0] + elif len(values) == 2: + # reduce to string concatenation + node = ExprNodes.binop_node(node.pos, '+', *values) + else: + node.values = values + return node + + def visit_MergedDictNode(self, node): + """Unpack **args in place if we can.""" + self.visitchildren(node) + args = [] + items = [] + + def add(arg): + if arg.is_dict_literal: + if items: + items[0].key_value_pairs.extend(arg.key_value_pairs) + else: + items.append(arg) + elif isinstance(arg, ExprNodes.MergedDictNode): + for child_arg in arg.keyword_args: + add(child_arg) + else: + if items: + args.append(items[0]) + del items[:] + args.append(arg) + + for arg in node.keyword_args: + add(arg) + if items: + args.append(items[0]) + + if len(args) == 1: + arg = args[0] + if arg.is_dict_literal or isinstance(arg, ExprNodes.MergedDictNode): + return arg + node.keyword_args[:] = args + self._calculate_const(node) + return node + + def visit_MergedSequenceNode(self, node): + """Unpack *args in place if we can.""" + self.visitchildren(node) + + is_set = node.type is Builtin.set_type + args = [] + values = [] + + def add(arg): + if (is_set and arg.is_set_literal) or (arg.is_sequence_constructor and not arg.mult_factor): + if values: + values[0].args.extend(arg.args) + else: + values.append(arg) + elif isinstance(arg, ExprNodes.MergedSequenceNode): + for child_arg in arg.args: + add(child_arg) + else: + if values: + args.append(values[0]) + del values[:] + args.append(arg) + + for arg in node.args: + add(arg) + if values: + args.append(values[0]) + + if len(args) == 1: + arg = args[0] + if ((is_set and arg.is_set_literal) or + (arg.is_sequence_constructor and arg.type is node.type) or + isinstance(arg, ExprNodes.MergedSequenceNode)): + return arg + node.args[:] = args + self._calculate_const(node) + return node + + def visit_SequenceNode(self, node): + """Unpack *args in place if we can.""" + self.visitchildren(node) + args = [] + for arg in node.args: + if not arg.is_starred: + args.append(arg) + elif arg.target.is_sequence_constructor and not arg.target.mult_factor: + args.extend(arg.target.args) + else: + args.append(arg) + node.args[:] = args + self._calculate_const(node) + return node + def visit_PrimaryCmpNode(self, node): # calculate constant partial results in the comparison cascade self.visitchildren(node, ['operand1']) @@ -4759,30 +4759,30 @@ class FinalOptimizePhase(Visitor.EnvTransform, Visitor.NodeRefCleanupMixin): else "optimize.unpack_method_calls")): # optimise simple Python methods calls if isinstance(node.arg_tuple, ExprNodes.TupleNode) and not ( - node.arg_tuple.mult_factor or (node.arg_tuple.is_literal and len(node.arg_tuple.args) > 1)): + node.arg_tuple.mult_factor or (node.arg_tuple.is_literal and len(node.arg_tuple.args) > 1)): # simple call, now exclude calls to objects that are definitely not methods may_be_a_method = True if function.type is Builtin.type_type: may_be_a_method = False - elif function.is_attribute: - if function.entry and function.entry.type.is_cfunction: - # optimised builtin method - may_be_a_method = False + elif function.is_attribute: + if function.entry and function.entry.type.is_cfunction: + # optimised builtin method + may_be_a_method = False elif function.is_name: - entry = function.entry - if entry.is_builtin or entry.type.is_cfunction: + entry = function.entry + if entry.is_builtin or entry.type.is_cfunction: may_be_a_method = False - elif entry.cf_assignments: + elif entry.cf_assignments: # local functions/classes are definitely not methods non_method_nodes = (ExprNodes.PyCFunctionNode, ExprNodes.ClassNode, ExprNodes.Py3ClassNode) may_be_a_method = any( assignment.rhs and not isinstance(assignment.rhs, non_method_nodes) - for assignment in entry.cf_assignments) + for assignment in entry.cf_assignments) if may_be_a_method: - if (node.self and function.is_attribute and - isinstance(function.obj, ExprNodes.CloneNode) and function.obj.arg is node.self): - # function self object was moved into a CloneNode => undo - function.obj = function.obj.arg + if (node.self and function.is_attribute and + isinstance(function.obj, ExprNodes.CloneNode) and function.obj.arg is node.self): + # function self object was moved into a CloneNode => undo + function.obj = function.obj.arg node = self.replace(node, ExprNodes.PyMethodCallNode.from_node( node, function=function, arg_tuple=node.arg_tuple, type=node.type)) return node diff --git a/contrib/tools/cython/Cython/Compiler/Options.py b/contrib/tools/cython/Cython/Compiler/Options.py index a90813e954..b3ffbcd927 100644 --- a/contrib/tools/cython/Cython/Compiler/Options.py +++ b/contrib/tools/cython/Cython/Compiler/Options.py @@ -4,182 +4,182 @@ from __future__ import absolute_import - -class ShouldBeFromDirective(object): - known_directives = [] +class ShouldBeFromDirective(object): + + known_directives = [] def __init__(self, options_name, directive_name=None, disallow=False): - self.options_name = options_name - self.directive_name = directive_name or options_name + self.options_name = options_name + self.directive_name = directive_name or options_name self.disallow = disallow - self.known_directives.append(self) - - def __nonzero__(self): - self._bad_access() - - def __int__(self): - self._bad_access() - - def _bad_access(self): - raise RuntimeError(repr(self)) - - def __repr__(self): - return ( - "Illegal access of '%s' from Options module rather than directive '%s'" - % (self.options_name, self.directive_name)) - - -""" -The members of this module are documented using autodata in -Cython/docs/src/reference/compilation.rst. -See http://www.sphinx-doc.org/en/master/ext/autodoc.html#directive-autoattribute -for how autodata works. -Descriptions of those members should start with a #: -Donc forget to keep the docs in sync by removing and adding -the members in both this file and the .rst file. -""" - -#: Whether or not to include docstring in the Python extension. If False, the binary size -#: will be smaller, but the ``__doc__`` attribute of any class or function will be an -#: empty string. + self.known_directives.append(self) + + def __nonzero__(self): + self._bad_access() + + def __int__(self): + self._bad_access() + + def _bad_access(self): + raise RuntimeError(repr(self)) + + def __repr__(self): + return ( + "Illegal access of '%s' from Options module rather than directive '%s'" + % (self.options_name, self.directive_name)) + + +""" +The members of this module are documented using autodata in +Cython/docs/src/reference/compilation.rst. +See http://www.sphinx-doc.org/en/master/ext/autodoc.html#directive-autoattribute +for how autodata works. +Descriptions of those members should start with a #: +Donc forget to keep the docs in sync by removing and adding +the members in both this file and the .rst file. +""" + +#: Whether or not to include docstring in the Python extension. If False, the binary size +#: will be smaller, but the ``__doc__`` attribute of any class or function will be an +#: empty string. docstrings = True -#: Embed the source code position in the docstrings of functions and classes. -embed_pos_in_docstring = False - -#: Copy the original source code line by line into C code comments -#: in the generated code file to help with understanding the output. -#: This is also required for coverage analysis. -emit_code_comments = True - -# undocumented -pre_import = None - -#: Decref global variables in each module on exit for garbage collection. -#: 0: None, 1+: interned objects, 2+: cdef globals, 3+: types objects -#: Mostly for reducing noise in Valgrind as it typically executes at process exit -#: (when all memory will be reclaimed anyways). -#: Note that directly or indirectly executed cleanup code that makes use of global -#: variables or types may no longer be safe when enabling the respective level since -#: there is no guaranteed order in which the (reference counted) objects will -#: be cleaned up. The order can change due to live references and reference cycles. +#: Embed the source code position in the docstrings of functions and classes. +embed_pos_in_docstring = False + +#: Copy the original source code line by line into C code comments +#: in the generated code file to help with understanding the output. +#: This is also required for coverage analysis. +emit_code_comments = True + +# undocumented +pre_import = None + +#: Decref global variables in each module on exit for garbage collection. +#: 0: None, 1+: interned objects, 2+: cdef globals, 3+: types objects +#: Mostly for reducing noise in Valgrind as it typically executes at process exit +#: (when all memory will be reclaimed anyways). +#: Note that directly or indirectly executed cleanup code that makes use of global +#: variables or types may no longer be safe when enabling the respective level since +#: there is no guaranteed order in which the (reference counted) objects will +#: be cleaned up. The order can change due to live references and reference cycles. generate_cleanup_code = False -#: Should tp_clear() set object fields to None instead of clearing them to NULL? -clear_to_none = True - -#: Generate an annotated HTML version of the input source files for debugging and optimisation purposes. -#: This has the same effect as the ``annotate`` argument in :func:`cythonize`. +#: Should tp_clear() set object fields to None instead of clearing them to NULL? +clear_to_none = True + +#: Generate an annotated HTML version of the input source files for debugging and optimisation purposes. +#: This has the same effect as the ``annotate`` argument in :func:`cythonize`. annotate = False -# When annotating source files in HTML, include coverage information from -# this file. -annotate_coverage_xml = None - -#: This will abort the compilation on the first error occurred rather than trying -#: to keep going and printing further error messages. +# When annotating source files in HTML, include coverage information from +# this file. +annotate_coverage_xml = None + +#: This will abort the compilation on the first error occurred rather than trying +#: to keep going and printing further error messages. fast_fail = False -#: Turn all warnings into errors. +#: Turn all warnings into errors. warning_errors = False -#: Make unknown names an error. Python raises a NameError when -#: encountering unknown names at runtime, whereas this option makes -#: them a compile time error. If you want full Python compatibility, -#: you should disable this option and also 'cache_builtins'. +#: Make unknown names an error. Python raises a NameError when +#: encountering unknown names at runtime, whereas this option makes +#: them a compile time error. If you want full Python compatibility, +#: you should disable this option and also 'cache_builtins'. error_on_unknown_names = True -#: Make uninitialized local variable reference a compile time error. -#: Python raises UnboundLocalError at runtime, whereas this option makes -#: them a compile time error. Note that this option affects only variables -#: of "python object" type. +#: Make uninitialized local variable reference a compile time error. +#: Python raises UnboundLocalError at runtime, whereas this option makes +#: them a compile time error. Note that this option affects only variables +#: of "python object" type. error_on_uninitialized = True -#: This will convert statements of the form ``for i in range(...)`` -#: to ``for i from ...`` when ``i`` is a C integer type, and the direction -#: (i.e. sign of step) can be determined. -#: WARNING: This may change the semantics if the range causes assignment to -#: i to overflow. Specifically, if this option is set, an error will be -#: raised before the loop is entered, whereas without this option the loop -#: will execute until an overflowing value is encountered. +#: This will convert statements of the form ``for i in range(...)`` +#: to ``for i from ...`` when ``i`` is a C integer type, and the direction +#: (i.e. sign of step) can be determined. +#: WARNING: This may change the semantics if the range causes assignment to +#: i to overflow. Specifically, if this option is set, an error will be +#: raised before the loop is entered, whereas without this option the loop +#: will execute until an overflowing value is encountered. convert_range = True -#: Perform lookups on builtin names only once, at module initialisation -#: time. This will prevent the module from getting imported if a -#: builtin name that it uses cannot be found during initialisation. -#: Default is True. -#: Note that some legacy builtins are automatically remapped -#: from their Python 2 names to their Python 3 names by Cython -#: when building in Python 3.x, -#: so that they do not get in the way even if this option is enabled. -cache_builtins = True - -#: Generate branch prediction hints to speed up error handling etc. -gcc_branch_hints = True - -#: Enable this to allow one to write ``your_module.foo = ...`` to overwrite the -#: definition if the cpdef function foo, at the cost of an extra dictionary -#: lookup on every call. -#: If this is false it generates only the Python wrapper and no override check. +#: Perform lookups on builtin names only once, at module initialisation +#: time. This will prevent the module from getting imported if a +#: builtin name that it uses cannot be found during initialisation. +#: Default is True. +#: Note that some legacy builtins are automatically remapped +#: from their Python 2 names to their Python 3 names by Cython +#: when building in Python 3.x, +#: so that they do not get in the way even if this option is enabled. +cache_builtins = True + +#: Generate branch prediction hints to speed up error handling etc. +gcc_branch_hints = True + +#: Enable this to allow one to write ``your_module.foo = ...`` to overwrite the +#: definition if the cpdef function foo, at the cost of an extra dictionary +#: lookup on every call. +#: If this is false it generates only the Python wrapper and no override check. lookup_module_cpdef = False -#: Whether or not to embed the Python interpreter, for use in making a -#: standalone executable or calling from external libraries. -#: This will provide a C function which initialises the interpreter and -#: executes the body of this module. -#: See `this demo <https://github.com/cython/cython/tree/master/Demos/embed>`_ -#: for a concrete example. -#: If true, the initialisation function is the C main() function, but -#: this option can also be set to a non-empty string to provide a function name explicitly. -#: Default is False. +#: Whether or not to embed the Python interpreter, for use in making a +#: standalone executable or calling from external libraries. +#: This will provide a C function which initialises the interpreter and +#: executes the body of this module. +#: See `this demo <https://github.com/cython/cython/tree/master/Demos/embed>`_ +#: for a concrete example. +#: If true, the initialisation function is the C main() function, but +#: this option can also be set to a non-empty string to provide a function name explicitly. +#: Default is False. embed = None # In previous iterations of Cython, globals() gave the first non-Cython module # globals in the call stack. Sage relies on this behavior for variable injection. -old_style_globals = ShouldBeFromDirective('old_style_globals') +old_style_globals = ShouldBeFromDirective('old_style_globals') -#: Allows cimporting from a pyx file without a pxd file. +#: Allows cimporting from a pyx file without a pxd file. cimport_from_pyx = False -#: Maximum number of dimensions for buffers -- set lower than number of -#: dimensions in numpy, as -#: slices are passed by value and involve a lot of copying. +#: Maximum number of dimensions for buffers -- set lower than number of +#: dimensions in numpy, as +#: slices are passed by value and involve a lot of copying. buffer_max_dims = 8 -#: Number of function closure instances to keep in a freelist (0: no freelists) +#: Number of function closure instances to keep in a freelist (0: no freelists) closure_freelist_size = 8 # Arcadia specific source_root = None -def get_directive_defaults(): - # To add an item to this list, all accesses should be changed to use the new - # directive, and the global option itself should be set to an instance of - # ShouldBeFromDirective. - for old_option in ShouldBeFromDirective.known_directives: - value = globals().get(old_option.options_name) - assert old_option.directive_name in _directive_defaults - if not isinstance(value, ShouldBeFromDirective): - if old_option.disallow: - raise RuntimeError( - "Option '%s' must be set from directive '%s'" % ( - old_option.option_name, old_option.directive_name)) - else: - # Warn? - _directive_defaults[old_option.directive_name] = value - return _directive_defaults +def get_directive_defaults(): + # To add an item to this list, all accesses should be changed to use the new + # directive, and the global option itself should be set to an instance of + # ShouldBeFromDirective. + for old_option in ShouldBeFromDirective.known_directives: + value = globals().get(old_option.options_name) + assert old_option.directive_name in _directive_defaults + if not isinstance(value, ShouldBeFromDirective): + if old_option.disallow: + raise RuntimeError( + "Option '%s' must be set from directive '%s'" % ( + old_option.option_name, old_option.directive_name)) + else: + # Warn? + _directive_defaults[old_option.directive_name] = value + return _directive_defaults # Declare compiler directives -_directive_defaults = { +_directive_defaults = { 'boundscheck' : True, 'nonecheck' : False, 'initializedcheck' : True, 'embedsignature' : False, 'auto_cpdef': False, 'auto_pickle': None, - 'cdivision': False, # was True before 0.12 + 'cdivision': False, # was True before 0.12 'cdivision_warnings': False, 'c_api_binop_methods': True, 'overflowcheck': False, @@ -187,28 +187,28 @@ _directive_defaults = { 'always_allow_keywords': False, 'allow_none_for_extension_args': True, 'wraparound' : True, - 'ccomplex' : False, # use C99/C++ for complex types and arith + 'ccomplex' : False, # use C99/C++ for complex types and arith 'callspec' : "", - 'nogil' : False, + 'nogil' : False, 'profile': False, 'linetrace': False, - 'emit_code_comments': True, # copy original source code into C code comments - 'annotation_typing': True, # read type declarations from Python function annotations + 'emit_code_comments': True, # copy original source code into C code comments + 'annotation_typing': True, # read type declarations from Python function annotations 'infer_types': None, 'infer_types.verbose': False, 'autotestdict': True, 'autotestdict.cdef': False, 'autotestdict.all': False, - 'language_level': None, - 'fast_getattr': False, # Undocumented until we come up with a better way to handle this everywhere. - 'py2_import': False, # For backward compatibility of Cython's source code in Py3 source mode + 'language_level': None, + 'fast_getattr': False, # Undocumented until we come up with a better way to handle this everywhere. + 'py2_import': False, # For backward compatibility of Cython's source code in Py3 source mode 'preliminary_late_includes_cy28': False, # Temporary directive in 0.28, to be removed in a later version (see GH#2079). 'iterable_coroutine': False, # Make async coroutines backwards compatible with the old asyncio yield-from syntax. 'c_string_type': 'bytes', 'c_string_encoding': '', - 'type_version_tag': True, # enables Py_TPFLAGS_HAVE_VERSION_TAG on extension types + 'type_version_tag': True, # enables Py_TPFLAGS_HAVE_VERSION_TAG on extension types 'unraisable_tracebacks': True, - 'old_style_globals': False, + 'old_style_globals': False, 'np_pythran': False, 'fast_gil': False, @@ -226,16 +226,16 @@ _directive_defaults = { # optimizations 'optimize.inline_defnode_calls': True, - 'optimize.unpack_method_calls': True, # increases code size when True - 'optimize.unpack_method_calls_in_pyinit': False, # uselessly increases code size when True + 'optimize.unpack_method_calls': True, # increases code size when True + 'optimize.unpack_method_calls_in_pyinit': False, # uselessly increases code size when True 'optimize.use_switch': True, # remove unreachable code 'remove_unreachable': True, # control flow debug directives - 'control_flow.dot_output': "", # Graphviz output filename - 'control_flow.dot_annotate_defs': False, # Annotate definitions + 'control_flow.dot_output': "", # Graphviz output filename + 'control_flow.dot_annotate_defs': False, # Annotate definitions # test support 'test_assert_path_exists' : [], @@ -243,8 +243,8 @@ _directive_defaults = { # experimental, subject to change 'binding': None, - - 'formal_grammar': False, + + 'formal_grammar': False, } # Extra warning directives @@ -300,49 +300,49 @@ def normalise_encoding_name(option_name, encoding): # Override types possibilities above, if needed directive_types = { - 'language_level': str, # values can be None/2/3/'3str', where None == 2+warning + 'language_level': str, # values can be None/2/3/'3str', where None == 2+warning 'auto_pickle': bool, - 'locals': dict, + 'locals': dict, 'final' : bool, # final cdef classes and methods - 'nogil' : bool, + 'nogil' : bool, 'internal' : bool, # cdef class visibility in the module dict - 'infer_types' : bool, # values can be True/None/False + 'infer_types' : bool, # values can be True/None/False 'binding' : bool, - 'cfunc' : None, # decorators do not take directive value + 'cfunc' : None, # decorators do not take directive value 'ccall' : None, 'inline' : None, 'staticmethod' : None, 'cclass' : None, - 'no_gc_clear' : bool, - 'no_gc' : bool, + 'no_gc_clear' : bool, + 'no_gc' : bool, 'returns' : type, - 'exceptval': type, # actually (type, check=True/False), but has its own parser + 'exceptval': type, # actually (type, check=True/False), but has its own parser 'set_initial_path': str, 'freelist': int, 'c_string_type': one_of('bytes', 'bytearray', 'str', 'unicode'), 'c_string_encoding': normalise_encoding_name, } -for key, val in _directive_defaults.items(): +for key, val in _directive_defaults.items(): if key not in directive_types: directive_types[key] = type(val) -directive_scopes = { # defaults to available everywhere +directive_scopes = { # defaults to available everywhere # 'module', 'function', 'class', 'with statement' 'auto_pickle': ('module', 'cclass'), 'final' : ('cclass', 'function'), - 'nogil' : ('function', 'with statement'), + 'nogil' : ('function', 'with statement'), 'inline' : ('function',), - 'cfunc' : ('function', 'with statement'), - 'ccall' : ('function', 'with statement'), + 'cfunc' : ('function', 'with statement'), + 'ccall' : ('function', 'with statement'), 'returns' : ('function',), 'exceptval' : ('function',), 'locals' : ('function',), 'staticmethod' : ('function',), # FIXME: analysis currently lacks more specific function scope 'no_gc_clear' : ('cclass',), - 'no_gc' : ('cclass',), + 'no_gc' : ('cclass',), 'internal' : ('cclass',), - 'cclass' : ('class', 'cclass', 'with statement'), + 'cclass' : ('class', 'cclass', 'with statement'), 'autotestdict' : ('module',), 'autotestdict.all' : ('module',), 'autotestdict.cdef' : ('module',), @@ -350,28 +350,28 @@ directive_scopes = { # defaults to available everywhere 'test_assert_path_exists' : ('function', 'class', 'cclass'), 'test_fail_if_path_exists' : ('function', 'class', 'cclass'), 'freelist': ('cclass',), - 'emit_code_comments': ('module',), + 'emit_code_comments': ('module',), 'annotation_typing': ('module',), # FIXME: analysis currently lacks more specific function scope # Avoid scope-specific to/from_py_functions for c_string. 'c_string_type': ('module',), 'c_string_encoding': ('module',), 'type_version_tag': ('module', 'cclass'), - 'language_level': ('module',), - # globals() could conceivably be controlled at a finer granularity, - # but that would complicate the implementation - 'old_style_globals': ('module',), + 'language_level': ('module',), + # globals() could conceivably be controlled at a finer granularity, + # but that would complicate the implementation + 'old_style_globals': ('module',), 'np_pythran': ('module',), 'fast_gil': ('module',), 'iterable_coroutine': ('module', 'function'), } - + def parse_directive_value(name, value, relaxed_bool=False): """ Parses value as an option value for the given name and returns the interpreted value. None is returned if the option does not exist. - >>> print(parse_directive_value('nonexisting', 'asdf asdfd')) + >>> print(parse_directive_value('nonexisting', 'asdf asdfd')) None >>> parse_directive_value('boundscheck', 'True') True @@ -395,21 +395,21 @@ def parse_directive_value(name, value, relaxed_bool=False): ValueError: c_string_type directive must be one of ('bytes', 'bytearray', 'str', 'unicode'), got 'unnicode' """ type = directive_types.get(name) - if not type: - return None + if not type: + return None orig_value = value if type is bool: value = str(value) - if value == 'True': - return True - if value == 'False': - return False + if value == 'True': + return True + if value == 'False': + return False if relaxed_bool: value = value.lower() - if value in ("true", "yes"): - return True - elif value in ("false", "no"): - return False + if value in ("true", "yes"): + return True + elif value in ("false", "no"): + return False raise ValueError("%s directive must be set to True or False, got '%s'" % ( name, orig_value)) elif type is int: @@ -425,7 +425,7 @@ def parse_directive_value(name, value, relaxed_bool=False): else: assert False - + def parse_directive_list(s, relaxed_bool=False, ignore_unknown=False, current_settings=None): """ @@ -461,16 +461,16 @@ def parse_directive_list(s, relaxed_bool=False, ignore_unknown=False, result = current_settings for item in s.split(','): item = item.strip() - if not item: - continue - if '=' not in item: - raise ValueError('Expected "=" in option "%s"' % item) - name, value = [s.strip() for s in item.strip().split('=', 1)] - if name not in _directive_defaults: + if not item: + continue + if '=' not in item: + raise ValueError('Expected "=" in option "%s"' % item) + name, value = [s.strip() for s in item.strip().split('=', 1)] + if name not in _directive_defaults: found = False if name.endswith('.all'): prefix = name[:-3] - for directive in _directive_defaults: + for directive in _directive_defaults: if directive.startswith(prefix): found = True parsed_value = parse_directive_value(directive, value, relaxed_bool=relaxed_bool) @@ -481,73 +481,73 @@ def parse_directive_list(s, relaxed_bool=False, ignore_unknown=False, parsed_value = parse_directive_value(name, value, relaxed_bool=relaxed_bool) result[name] = parsed_value return result - - -def parse_variable_value(value): - """ - Parses value as an option value for the given name and returns - the interpreted value. - - >>> parse_variable_value('True') - True - >>> parse_variable_value('true') - 'true' - >>> parse_variable_value('us-ascii') - 'us-ascii' - >>> parse_variable_value('str') - 'str' - >>> parse_variable_value('123') - 123 - >>> parse_variable_value('1.23') - 1.23 - - """ - if value == "True": - return True - elif value == "False": - return False - elif value == "None": - return None - elif value.isdigit(): - return int(value) - else: - try: - value = float(value) - except Exception: - # Not a float - pass - return value - - -def parse_compile_time_env(s, current_settings=None): - """ - Parses a comma-separated list of pragma options. Whitespace - is not considered. - - >>> parse_compile_time_env(' ') - {} - >>> (parse_compile_time_env('HAVE_OPENMP=True') == - ... {'HAVE_OPENMP': True}) - True - >>> parse_compile_time_env(' asdf') - Traceback (most recent call last): - ... - ValueError: Expected "=" in option "asdf" - >>> parse_compile_time_env('NUM_THREADS=4') == {'NUM_THREADS': 4} - True - >>> parse_compile_time_env('unknown=anything') == {'unknown': 'anything'} - True - """ - if current_settings is None: - result = {} - else: - result = current_settings - for item in s.split(','): - item = item.strip() - if not item: - continue - if '=' not in item: - raise ValueError('Expected "=" in option "%s"' % item) - name, value = [s.strip() for s in item.split('=', 1)] - result[name] = parse_variable_value(value) - return result + + +def parse_variable_value(value): + """ + Parses value as an option value for the given name and returns + the interpreted value. + + >>> parse_variable_value('True') + True + >>> parse_variable_value('true') + 'true' + >>> parse_variable_value('us-ascii') + 'us-ascii' + >>> parse_variable_value('str') + 'str' + >>> parse_variable_value('123') + 123 + >>> parse_variable_value('1.23') + 1.23 + + """ + if value == "True": + return True + elif value == "False": + return False + elif value == "None": + return None + elif value.isdigit(): + return int(value) + else: + try: + value = float(value) + except Exception: + # Not a float + pass + return value + + +def parse_compile_time_env(s, current_settings=None): + """ + Parses a comma-separated list of pragma options. Whitespace + is not considered. + + >>> parse_compile_time_env(' ') + {} + >>> (parse_compile_time_env('HAVE_OPENMP=True') == + ... {'HAVE_OPENMP': True}) + True + >>> parse_compile_time_env(' asdf') + Traceback (most recent call last): + ... + ValueError: Expected "=" in option "asdf" + >>> parse_compile_time_env('NUM_THREADS=4') == {'NUM_THREADS': 4} + True + >>> parse_compile_time_env('unknown=anything') == {'unknown': 'anything'} + True + """ + if current_settings is None: + result = {} + else: + result = current_settings + for item in s.split(','): + item = item.strip() + if not item: + continue + if '=' not in item: + raise ValueError('Expected "=" in option "%s"' % item) + name, value = [s.strip() for s in item.split('=', 1)] + result[name] = parse_variable_value(value) + return result diff --git a/contrib/tools/cython/Cython/Compiler/ParseTreeTransforms.pxd b/contrib/tools/cython/Cython/Compiler/ParseTreeTransforms.pxd index c71407c748..2c17901fa4 100644 --- a/contrib/tools/cython/Cython/Compiler/ParseTreeTransforms.pxd +++ b/contrib/tools/cython/Cython/Compiler/ParseTreeTransforms.pxd @@ -70,9 +70,9 @@ cdef class CreateClosureClasses(CythonTransform): cdef create_class_from_scope(self, node, target_module_scope, inner_node=*) cdef find_entries_used_in_closures(self, node) -#cdef class InjectGilHandling(VisitorTransform, SkipDeclarations): -# cdef bint nogil - +#cdef class InjectGilHandling(VisitorTransform, SkipDeclarations): +# cdef bint nogil + cdef class GilCheck(VisitorTransform): cdef list env_stack cdef bint nogil diff --git a/contrib/tools/cython/Cython/Compiler/ParseTreeTransforms.py b/contrib/tools/cython/Cython/Compiler/ParseTreeTransforms.py index 32bc736e00..0da3670cae 100644 --- a/contrib/tools/cython/Cython/Compiler/ParseTreeTransforms.py +++ b/contrib/tools/cython/Cython/Compiler/ParseTreeTransforms.py @@ -4,11 +4,11 @@ import cython cython.declare(PyrexTypes=object, Naming=object, ExprNodes=object, Nodes=object, Options=object, UtilNodes=object, LetNode=object, LetRefNode=object, TreeFragment=object, EncodedString=object, - error=object, warning=object, copy=object, _unicode=object) + error=object, warning=object, copy=object, _unicode=object) -import copy +import copy import hashlib - + from . import PyrexTypes from . import Naming from . import ExprNodes @@ -19,9 +19,9 @@ from . import Errors from .Visitor import VisitorTransform, TreeVisitor from .Visitor import CythonTransform, EnvTransform, ScopeTrackingTransform -from .UtilNodes import LetNode, LetRefNode +from .UtilNodes import LetNode, LetRefNode from .TreeFragment import TreeFragment -from .StringEncoding import EncodedString, _unicode +from .StringEncoding import EncodedString, _unicode from .Errors import error, warning, CompileError, InternalError from .Code import UtilityCode @@ -52,7 +52,7 @@ class SkipDeclarations(object): def visit_CStructOrUnionDefNode(self, node): return node - + class NormalizeTree(CythonTransform): """ This transform fixes up a few things after parsing @@ -187,7 +187,7 @@ class PostParse(ScopeTrackingTransform): body = Nodes.ReturnStatNode( node.result_expr.pos, value=node.result_expr) node.def_node = Nodes.DefNode( - node.pos, name=node.name, + node.pos, name=node.name, args=node.args, star_arg=node.star_arg, starstar_arg=node.starstar_arg, body=body, doc=None) @@ -254,7 +254,7 @@ class PostParse(ScopeTrackingTransform): newdecls.append(decl) node.declarators = newdecls return stats - except PostParseError as e: + except PostParseError as e: # An error in a cdef clause is ok, simply remove the declaration # and try to move on to report more errors self.context.nonfatal_error(e) @@ -419,11 +419,11 @@ def sort_common_subsequences(items): for pos, item in enumerate(items): key = item[1] # the ResultRefNode which has already been injected into the sequences new_pos = pos - for i in range(pos-1, -1, -1): + for i in range(pos-1, -1, -1): if lower_than(key, items[i][0]): new_pos = i if new_pos != pos: - for i in range(pos, new_pos, -1): + for i in range(pos, new_pos, -1): items[i] = items[i-1] items[new_pos] = item @@ -459,7 +459,7 @@ def flatten_parallel_assignments(input, output): rhs_args = unpack_string_to_character_literals(rhs) rhs_size = len(rhs_args) - lhs_targets = [[] for _ in range(rhs_size)] + lhs_targets = [[] for _ in range(rhs_size)] starred_assignments = [] for lhs in input[:-1]: if not lhs.is_sequence_constructor: @@ -613,8 +613,8 @@ class TrackNumpyAttributes(VisitorTransform, SkipDeclarations): def visit_AttributeNode(self, node): self.visitchildren(node) - obj = node.obj - if (obj.is_name and obj.name in self.numpy_module_names) or obj.is_numpy_attribute: + obj = node.obj + if (obj.is_name and obj.name in self.numpy_module_names) or obj.is_numpy_attribute: node.is_numpy_attribute = True return node @@ -656,9 +656,9 @@ class InterpretCompilerDirectives(CythonTransform): 'operator.predecrement' : ExprNodes.inc_dec_constructor(True, '--'), 'operator.postincrement': ExprNodes.inc_dec_constructor(False, '++'), 'operator.postdecrement': ExprNodes.inc_dec_constructor(False, '--'), - 'operator.typeid' : ExprNodes.TypeidNode, + 'operator.typeid' : ExprNodes.TypeidNode, - # For backwards compatibility. + # For backwards compatibility. 'address': ExprNodes.AmpersandNode, } @@ -669,13 +669,13 @@ class InterpretCompilerDirectives(CythonTransform): special_methods = set(['declare', 'union', 'struct', 'typedef', 'sizeof', 'cast', 'pointer', 'compiled', 'NULL', 'fused_type', 'parallel']) - special_methods.update(unop_method_nodes) + special_methods.update(unop_method_nodes) valid_parallel_directives = set([ "parallel", "prange", "threadid", - #"threadsavailable", + #"threadsavailable", ]) def __init__(self, context, compilation_directive_defaults): @@ -683,9 +683,9 @@ class InterpretCompilerDirectives(CythonTransform): self.cython_module_names = set() self.directive_names = {'staticmethod': 'staticmethod'} self.parallel_directives = {} - directives = copy.deepcopy(Options.get_directive_defaults()) + directives = copy.deepcopy(Options.get_directive_defaults()) for key, value in compilation_directive_defaults.items(): - directives[_unicode(key)] = copy.deepcopy(value) + directives[_unicode(key)] = copy.deepcopy(value) self.directives = directives def check_directive_scope(self, pos, directive, scope): @@ -695,13 +695,13 @@ class InterpretCompilerDirectives(CythonTransform): 'is not allowed in %s scope' % (directive, scope))) return False else: - if directive not in Options.directive_types: + if directive not in Options.directive_types: error(pos, "Invalid directive: '%s'." % (directive,)) return True # Set up processing and handle the cython: comments. def visit_ModuleNode(self, node): - for key in sorted(node.directive_comments): + for key in sorted(node.directive_comments): if not self.check_directive_scope(node.pos, key, 'module'): self.wrong_scope_error(node.pos, key, 'module') del node.directive_comments[key] @@ -917,7 +917,7 @@ class InterpretCompilerDirectives(CythonTransform): directivetype = Options.directive_types.get(optname) if len(args) == 1 and isinstance(args[0], ExprNodes.NoneNode): - return optname, Options.get_directive_defaults()[optname] + return optname, Options.get_directive_defaults()[optname] elif directivetype is bool: if kwds is not None or len(args) != 1 or not isinstance(args[0], ExprNodes.BoolNode): raise PostParseError(pos, @@ -958,34 +958,34 @@ class InterpretCompilerDirectives(CythonTransform): else: assert False - def visit_with_directives(self, node, directives): - if not directives: - return self.visit_Node(node) - - old_directives = self.directives - new_directives = dict(old_directives) - new_directives.update(directives) - - if new_directives == old_directives: - return self.visit_Node(node) - - self.directives = new_directives - retbody = self.visit_Node(node) - self.directives = old_directives - - if not isinstance(retbody, Nodes.StatListNode): - retbody = Nodes.StatListNode(node.pos, stats=[retbody]) - return Nodes.CompilerDirectivesNode( - pos=retbody.pos, body=retbody, directives=new_directives) - + def visit_with_directives(self, node, directives): + if not directives: + return self.visit_Node(node) + + old_directives = self.directives + new_directives = dict(old_directives) + new_directives.update(directives) + + if new_directives == old_directives: + return self.visit_Node(node) + + self.directives = new_directives + retbody = self.visit_Node(node) + self.directives = old_directives + + if not isinstance(retbody, Nodes.StatListNode): + retbody = Nodes.StatListNode(node.pos, stats=[retbody]) + return Nodes.CompilerDirectivesNode( + pos=retbody.pos, body=retbody, directives=new_directives) + # Handle decorators def visit_FuncDefNode(self, node): directives = self._extract_directives(node, 'function') - return self.visit_with_directives(node, directives) + return self.visit_with_directives(node, directives) def visit_CVarDefNode(self, node): directives = self._extract_directives(node, 'function') - for name, value in directives.items(): + for name, value in directives.items(): if name == 'locals': node.directive_locals = value elif name not in ('final', 'staticmethod'): @@ -993,19 +993,19 @@ class InterpretCompilerDirectives(CythonTransform): node.pos, "Cdef functions can only take cython.locals(), " "staticmethod, or final decorators, got %s." % name)) - return self.visit_with_directives(node, directives) + return self.visit_with_directives(node, directives) def visit_CClassDefNode(self, node): directives = self._extract_directives(node, 'cclass') - return self.visit_with_directives(node, directives) + return self.visit_with_directives(node, directives) def visit_CppClassNode(self, node): directives = self._extract_directives(node, 'cppclass') - return self.visit_with_directives(node, directives) + return self.visit_with_directives(node, directives) def visit_PyClassDefNode(self, node): directives = self._extract_directives(node, 'class') - return self.visit_with_directives(node, directives) + return self.visit_with_directives(node, directives) def _extract_directives(self, node, scope_name): if not node.decorators: @@ -1052,7 +1052,7 @@ class InterpretCompilerDirectives(CythonTransform): optdict[name] = value return optdict - # Handle with-statements + # Handle with-statements def visit_WithStatNode(self, node): directive_dict = {} for directive in self.try_to_parse_directives(node.manager) or []: @@ -1252,19 +1252,19 @@ class WithTransform(CythonTransform, SkipDeclarations): def visit_WithStatNode(self, node): self.visitchildren(node, 'body') pos = node.pos - is_async = node.is_async + is_async = node.is_async body, target, manager = node.body, node.target, node.manager node.enter_call = ExprNodes.SimpleCallNode( pos, function=ExprNodes.AttributeNode( pos, obj=ExprNodes.CloneNode(manager), - attribute=EncodedString('__aenter__' if is_async else '__enter__'), + attribute=EncodedString('__aenter__' if is_async else '__enter__'), is_special_lookup=True), args=[], is_temp=True) - if is_async: - node.enter_call = ExprNodes.AwaitExprNode(pos, arg=node.enter_call) - + if is_async: + node.enter_call = ExprNodes.AwaitExprNode(pos, arg=node.enter_call) + if target is not None: body = Nodes.StatListNode( pos, stats=[ @@ -1282,7 +1282,7 @@ class WithTransform(CythonTransform, SkipDeclarations): pos, operand=ExprNodes.WithExitCallNode( pos, with_stat=node, test_if_run=False, - args=excinfo_target, + args=excinfo_target, await_expr=ExprNodes.AwaitExprNode(pos, arg=None) if is_async else None)), body=Nodes.ReraiseStatNode(pos), ), @@ -1304,7 +1304,7 @@ class WithTransform(CythonTransform, SkipDeclarations): pos, with_stat=node, test_if_run=True, args=ExprNodes.TupleNode( - pos, args=[ExprNodes.NoneNode(pos) for _ in range(3)]), + pos, args=[ExprNodes.NoneNode(pos) for _ in range(3)]), await_expr=ExprNodes.AwaitExprNode(pos, arg=None) if is_async else None)), handle_error_case=False, ) @@ -1316,76 +1316,76 @@ class WithTransform(CythonTransform, SkipDeclarations): class DecoratorTransform(ScopeTrackingTransform, SkipDeclarations): - """ - Transforms method decorators in cdef classes into nested calls or properties. + """ + Transforms method decorators in cdef classes into nested calls or properties. - Python-style decorator properties are transformed into a PropertyNode - with up to the three getter, setter and deleter DefNodes. - The functional style isn't supported yet. + Python-style decorator properties are transformed into a PropertyNode + with up to the three getter, setter and deleter DefNodes. + The functional style isn't supported yet. """ - _properties = None - - _map_property_attribute = { - 'getter': '__get__', - 'setter': '__set__', - 'deleter': '__del__', - }.get - - def visit_CClassDefNode(self, node): - if self._properties is None: - self._properties = [] - self._properties.append({}) - super(DecoratorTransform, self).visit_CClassDefNode(node) - self._properties.pop() - return node - - def visit_PropertyNode(self, node): - # Low-level warning for other code until we can convert all our uses over. - level = 2 if isinstance(node.pos[0], str) else 0 - warning(node.pos, "'property %s:' syntax is deprecated, use '@property'" % node.name, level) - return node - - def visit_DefNode(self, node): + _properties = None + + _map_property_attribute = { + 'getter': '__get__', + 'setter': '__set__', + 'deleter': '__del__', + }.get + + def visit_CClassDefNode(self, node): + if self._properties is None: + self._properties = [] + self._properties.append({}) + super(DecoratorTransform, self).visit_CClassDefNode(node) + self._properties.pop() + return node + + def visit_PropertyNode(self, node): + # Low-level warning for other code until we can convert all our uses over. + level = 2 if isinstance(node.pos[0], str) else 0 + warning(node.pos, "'property %s:' syntax is deprecated, use '@property'" % node.name, level) + return node + + def visit_DefNode(self, node): scope_type = self.scope_type - node = self.visit_FuncDefNode(node) - if scope_type != 'cclass' or not node.decorators: - return node - - # transform @property decorators - properties = self._properties[-1] - for decorator_node in node.decorators[::-1]: - decorator = decorator_node.decorator - if decorator.is_name and decorator.name == 'property': - if len(node.decorators) > 1: - return self._reject_decorated_property(node, decorator_node) - name = node.name - node.name = EncodedString('__get__') - node.decorators.remove(decorator_node) - stat_list = [node] - if name in properties: - prop = properties[name] - prop.pos = node.pos - prop.doc = node.doc - prop.body.stats = stat_list - return [] - prop = Nodes.PropertyNode(node.pos, name=name) - prop.doc = node.doc - prop.body = Nodes.StatListNode(node.pos, stats=stat_list) - properties[name] = prop - return [prop] - elif decorator.is_attribute and decorator.obj.name in properties: - handler_name = self._map_property_attribute(decorator.attribute) - if handler_name: + node = self.visit_FuncDefNode(node) + if scope_type != 'cclass' or not node.decorators: + return node + + # transform @property decorators + properties = self._properties[-1] + for decorator_node in node.decorators[::-1]: + decorator = decorator_node.decorator + if decorator.is_name and decorator.name == 'property': + if len(node.decorators) > 1: + return self._reject_decorated_property(node, decorator_node) + name = node.name + node.name = EncodedString('__get__') + node.decorators.remove(decorator_node) + stat_list = [node] + if name in properties: + prop = properties[name] + prop.pos = node.pos + prop.doc = node.doc + prop.body.stats = stat_list + return [] + prop = Nodes.PropertyNode(node.pos, name=name) + prop.doc = node.doc + prop.body = Nodes.StatListNode(node.pos, stats=stat_list) + properties[name] = prop + return [prop] + elif decorator.is_attribute and decorator.obj.name in properties: + handler_name = self._map_property_attribute(decorator.attribute) + if handler_name: if decorator.obj.name != node.name: # CPython does not generate an error or warning, but not something useful either. error(decorator_node.pos, "Mismatching property names, expected '%s', got '%s'" % ( decorator.obj.name, node.name)) elif len(node.decorators) > 1: - return self._reject_decorated_property(node, decorator_node) + return self._reject_decorated_property(node, decorator_node) else: return self._add_to_property(properties, node, handler_name, decorator_node) - + # we clear node.decorators, so we need to set the # is_staticmethod/is_classmethod attributes now for decorator in node.decorators: @@ -1394,61 +1394,61 @@ class DecoratorTransform(ScopeTrackingTransform, SkipDeclarations): node.is_classmethod |= func.name == 'classmethod' node.is_staticmethod |= func.name == 'staticmethod' - # transform normal decorators + # transform normal decorators decs = node.decorators node.decorators = None return self.chain_decorators(node, decs, node.name) - - @staticmethod - def _reject_decorated_property(node, decorator_node): - # restrict transformation to outermost decorator as wrapped properties will probably not work - for deco in node.decorators: - if deco != decorator_node: - error(deco.pos, "Property methods with additional decorators are not supported") - return node - - @staticmethod - def _add_to_property(properties, node, name, decorator): - prop = properties[node.name] - node.name = name - node.decorators.remove(decorator) - stats = prop.body.stats - for i, stat in enumerate(stats): - if stat.name == name: - stats[i] = node - break - else: - stats.append(node) - return [] - - @staticmethod - def chain_decorators(node, decorators, name): - """ - Decorators are applied directly in DefNode and PyClassDefNode to avoid - reassignments to the function/class name - except for cdef class methods. - For those, the reassignment is required as methods are originally - defined in the PyMethodDef struct. - - The IndirectionNode allows DefNode to override the decorator. - """ - decorator_result = ExprNodes.NameNode(node.pos, name=name) + + @staticmethod + def _reject_decorated_property(node, decorator_node): + # restrict transformation to outermost decorator as wrapped properties will probably not work + for deco in node.decorators: + if deco != decorator_node: + error(deco.pos, "Property methods with additional decorators are not supported") + return node + + @staticmethod + def _add_to_property(properties, node, name, decorator): + prop = properties[node.name] + node.name = name + node.decorators.remove(decorator) + stats = prop.body.stats + for i, stat in enumerate(stats): + if stat.name == name: + stats[i] = node + break + else: + stats.append(node) + return [] + + @staticmethod + def chain_decorators(node, decorators, name): + """ + Decorators are applied directly in DefNode and PyClassDefNode to avoid + reassignments to the function/class name - except for cdef class methods. + For those, the reassignment is required as methods are originally + defined in the PyMethodDef struct. + + The IndirectionNode allows DefNode to override the decorator. + """ + decorator_result = ExprNodes.NameNode(node.pos, name=name) for decorator in decorators[::-1]: decorator_result = ExprNodes.SimpleCallNode( decorator.pos, - function=decorator.decorator, - args=[decorator_result]) + function=decorator.decorator, + args=[decorator_result]) - name_node = ExprNodes.NameNode(node.pos, name=name) + name_node = ExprNodes.NameNode(node.pos, name=name) reassignment = Nodes.SingleAssignmentNode( node.pos, - lhs=name_node, - rhs=decorator_result) + lhs=name_node, + rhs=decorator_result) reassignment = Nodes.IndirectionNode([reassignment]) node.decorator_indirection = reassignment return [node, reassignment] - + class CnameDirectivesTransform(CythonTransform, SkipDeclarations): """ Only part of the CythonUtilityCode pipeline. Must be run before @@ -1482,7 +1482,7 @@ class CnameDirectivesTransform(CythonTransform, SkipDeclarations): raise AssertionError( "argument to cname decorator must be a string literal") - cname = args[0].compile_time_value(None) + cname = args[0].compile_time_value(None) del node.decorators[i] node = Nodes.CnameDecoratorNode(pos=node.pos, node=node, cname=cname) @@ -1708,8 +1708,8 @@ if VALUE is not None: # so it can be pickled *after* self is memoized. unpickle_func = TreeFragment(u""" def %(unpickle_func_name)s(__pyx_type, long __pyx_checksum, __pyx_state): - cdef object __pyx_PickleError - cdef object __pyx_result + cdef object __pyx_PickleError + cdef object __pyx_result if __pyx_checksum != %(checksum)s: from pickle import PickleError as __pyx_PickleError raise __pyx_PickleError("Incompatible checksums (%%s vs %(checksum)s = (%(members)s))" %% __pyx_checksum) @@ -1738,8 +1738,8 @@ if VALUE is not None: pickle_func = TreeFragment(u""" def __reduce_cython__(self): - cdef tuple state - cdef object _dict + cdef tuple state + cdef object _dict cdef bint use_setstate state = (%(members)s) _dict = getattr(self, '__dict__', None) @@ -1788,7 +1788,7 @@ if VALUE is not None: if decorators: transform = DecoratorTransform(self.context) def_node = node.node - _, reassignments = transform.chain_decorators( + _, reassignments = transform.chain_decorators( def_node, decorators, def_node.name) reassignments.analyse_declarations(env) node = [node, reassignments] @@ -1801,7 +1801,7 @@ if VALUE is not None: node.stats.insert(0, node.py_func) node.py_func = self.visit(node.py_func) node.update_fused_defnode_entry(env) - pycfunc = ExprNodes.PyCFunctionNode.from_defnode(node.py_func, binding=True) + pycfunc = ExprNodes.PyCFunctionNode.from_defnode(node.py_func, binding=True) pycfunc = ExprNodes.ProxyNode(pycfunc.coerce_to_temp(env)) node.resulting_fused_function = pycfunc # Create assignment node for our def function @@ -1853,8 +1853,8 @@ if VALUE is not None: node.body = Nodes.NogilTryFinallyStatNode( node.body.pos, body=node.body, - finally_clause=Nodes.EnsureGILNode(node.body.pos), - finally_except_clause=Nodes.EnsureGILNode(node.body.pos)) + finally_clause=Nodes.EnsureGILNode(node.body.pos), + finally_except_clause=Nodes.EnsureGILNode(node.body.pos)) def _handle_fused(self, node): if node.is_generator and node.has_fused_arguments: @@ -1905,8 +1905,8 @@ if VALUE is not None: def visit_DefNode(self, node): node = self.visit_FuncDefNode(node) env = self.current_env() - if isinstance(node, Nodes.DefNode) and node.is_wrapper: - env = env.parent_scope + if isinstance(node, Nodes.DefNode) and node.is_wrapper: + env = env.parent_scope if (not isinstance(node, Nodes.DefNode) or node.fused_py_func or node.is_generator_body or not node.needs_assignment_synthesis(env)): @@ -1930,7 +1930,7 @@ if VALUE is not None: else: binding = self.current_directives.get('binding') rhs = ExprNodes.PyCFunctionNode.from_defnode(node, binding) - node.code_object = rhs.code_object + node.code_object = rhs.code_object if node.is_generator: node.gbody.code_object = node.code_object @@ -2161,28 +2161,28 @@ class CalculateQualifiedNamesTransform(EnvTransform): return node def visit_PyCFunctionNode(self, node): - orig_qualified_name = self.qualified_name[:] - if node.def_node.is_wrapper and self.qualified_name and self.qualified_name[-1] == '<locals>': - self.qualified_name.pop() - self._set_qualname(node) - else: - self._set_qualname(node, node.def_node.name) + orig_qualified_name = self.qualified_name[:] + if node.def_node.is_wrapper and self.qualified_name and self.qualified_name[-1] == '<locals>': + self.qualified_name.pop() + self._set_qualname(node) + else: + self._set_qualname(node, node.def_node.name) self.visitchildren(node) - self.qualified_name = orig_qualified_name + self.qualified_name = orig_qualified_name return node def visit_DefNode(self, node): - if node.is_wrapper and self.qualified_name: - assert self.qualified_name[-1] == '<locals>', self.qualified_name - orig_qualified_name = self.qualified_name[:] - self.qualified_name.pop() - self._set_qualname(node) - self._super_visit_FuncDefNode(node) - self.qualified_name = orig_qualified_name - else: - self._set_qualname(node, node.name) - self.visit_FuncDefNode(node) - return node + if node.is_wrapper and self.qualified_name: + assert self.qualified_name[-1] == '<locals>', self.qualified_name + orig_qualified_name = self.qualified_name[:] + self.qualified_name.pop() + self._set_qualname(node) + self._super_visit_FuncDefNode(node) + self.qualified_name = orig_qualified_name + else: + self._set_qualname(node, node.name) + self.visit_FuncDefNode(node) + return node def visit_FuncDefNode(self, node): orig_qualified_name = self.qualified_name[:] @@ -2273,26 +2273,26 @@ class ExpandInplaceOperators(EnvTransform): if lhs.type.is_cpp_class: # No getting around this exact operator here. return node - if isinstance(lhs, ExprNodes.BufferIndexNode): - # There is code to handle this case in InPlaceAssignmentNode + if isinstance(lhs, ExprNodes.BufferIndexNode): + # There is code to handle this case in InPlaceAssignmentNode return node env = self.current_env() def side_effect_free_reference(node, setting=False): - if node.is_name: + if node.is_name: return node, [] elif node.type.is_pyobject and not setting: node = LetRefNode(node) return node, [node] - elif node.is_subscript: + elif node.is_subscript: base, temps = side_effect_free_reference(node.base) index = LetRefNode(node.index) return ExprNodes.IndexNode(node.pos, base=base, index=index), temps + [index] - elif node.is_attribute: + elif node.is_attribute: obj, temps = side_effect_free_reference(node.obj) return ExprNodes.AttributeNode(node.pos, obj=obj, attribute=node.attribute), temps - elif isinstance(node, ExprNodes.BufferIndexNode): - raise ValueError("Don't allow things like attributes of buffer indexing operations") + elif isinstance(node, ExprNodes.BufferIndexNode): + raise ValueError("Don't allow things like attributes of buffer indexing operations") else: node = LetRefNode(node) return node, [node] @@ -2333,7 +2333,7 @@ class AdjustDefByDirectives(CythonTransform, SkipDeclarations): @cython.cclass @cython.ccall @cython.inline - @cython.nogil + @cython.nogil """ def visit_ModuleNode(self, node): @@ -2353,7 +2353,7 @@ class AdjustDefByDirectives(CythonTransform, SkipDeclarations): modifiers = [] if 'inline' in self.directives: modifiers.append('inline') - nogil = self.directives.get('nogil') + nogil = self.directives.get('nogil') except_val = self.directives.get('exceptval') return_type_node = self.directives.get('returns') if return_type_node is None and self.directives['annotation_typing']: @@ -2366,7 +2366,7 @@ class AdjustDefByDirectives(CythonTransform, SkipDeclarations): except_val = (None, False) if 'ccall' in self.directives: node = node.as_cfunction( - overridable=True, modifiers=modifiers, nogil=nogil, + overridable=True, modifiers=modifiers, nogil=nogil, returns=return_type_node, except_val=except_val) return self.visit(node) if 'cfunc' in self.directives: @@ -2374,21 +2374,21 @@ class AdjustDefByDirectives(CythonTransform, SkipDeclarations): error(node.pos, "cfunc directive is not allowed here") else: node = node.as_cfunction( - overridable=False, modifiers=modifiers, nogil=nogil, + overridable=False, modifiers=modifiers, nogil=nogil, returns=return_type_node, except_val=except_val) return self.visit(node) if 'inline' in modifiers: error(node.pos, "Python functions cannot be declared 'inline'") - if nogil: - # TODO: turn this into a "with gil" declaration. - error(node.pos, "Python functions cannot be declared 'nogil'") + if nogil: + # TODO: turn this into a "with gil" declaration. + error(node.pos, "Python functions cannot be declared 'nogil'") self.visitchildren(node) return node - def visit_LambdaNode(self, node): - # No directives should modify lambdas or generator expressions (and also nothing in them). - return node - + def visit_LambdaNode(self, node): + # No directives should modify lambdas or generator expressions (and also nothing in them). + return node + def visit_PyClassDefNode(self, node): if 'cclass' in self.directives: node = node.as_cclass() @@ -2437,8 +2437,8 @@ class AlignFunctionDefinitions(CythonTransform): if pxd_def is None: pxd_def = self.scope.lookup(node.class_name) if pxd_def: - if not pxd_def.defined_in_pxd: - return node + if not pxd_def.defined_in_pxd: + return node outer_scope = self.scope self.scope = pxd_def.type.scope self.visitchildren(node) @@ -2518,13 +2518,13 @@ class RemoveUnreachableCode(CythonTransform): node.else_clause = None return node - def visit_TryFinallyStatNode(self, node): - self.visitchildren(node) - if node.finally_clause.is_terminator: - node.is_terminator = True - return node + def visit_TryFinallyStatNode(self, node): + self.visitchildren(node) + if node.finally_clause.is_terminator: + node.is_terminator = True + return node + - class YieldNodeCollector(TreeVisitor): def __init__(self): @@ -2545,11 +2545,11 @@ class YieldNodeCollector(TreeVisitor): self.has_yield = True self.visitchildren(node) - def visit_AwaitExprNode(self, node): + def visit_AwaitExprNode(self, node): self.yields.append(node) self.has_await = True - self.visitchildren(node) - + self.visitchildren(node) + def visit_ReturnStatNode(self, node): self.visitchildren(node) if node.value: @@ -2576,12 +2576,12 @@ class YieldNodeCollector(TreeVisitor): def visit_GeneratorExpressionNode(self, node): pass - def visit_CArgDeclNode(self, node): - # do not look into annotations - # FIXME: support (yield) in default arguments (currently crashes) - pass + def visit_CArgDeclNode(self, node): + # do not look into annotations + # FIXME: support (yield) in default arguments (currently crashes) + pass + - class MarkClosureVisitor(CythonTransform): def visit_ModuleNode(self, node): @@ -2598,7 +2598,7 @@ class MarkClosureVisitor(CythonTransform): collector = YieldNodeCollector() collector.visitchildren(node) - if node.is_async_def: + if node.is_async_def: coroutine_type = Nodes.AsyncDefNode if collector.has_yield: coroutine_type = Nodes.AsyncGenNode @@ -2612,30 +2612,30 @@ class MarkClosureVisitor(CythonTransform): return node elif collector.has_yield: coroutine_type = Nodes.GeneratorDefNode - else: - return node + else: + return node for i, yield_expr in enumerate(collector.yields, 1): - yield_expr.label_num = i + yield_expr.label_num = i for retnode in collector.returns + collector.finallys + collector.excepts: - retnode.in_generator = True + retnode.in_generator = True - gbody = Nodes.GeneratorBodyDefNode( + gbody = Nodes.GeneratorBodyDefNode( pos=node.pos, name=node.name, body=node.body, is_async_gen_body=node.is_async_def and collector.has_yield) coroutine = coroutine_type( - pos=node.pos, name=node.name, args=node.args, - star_arg=node.star_arg, starstar_arg=node.starstar_arg, - doc=node.doc, decorators=node.decorators, - gbody=gbody, lambda_name=node.lambda_name, - return_type_annotation=node.return_type_annotation) - return coroutine - + pos=node.pos, name=node.name, args=node.args, + star_arg=node.star_arg, starstar_arg=node.starstar_arg, + doc=node.doc, decorators=node.decorators, + gbody=gbody, lambda_name=node.lambda_name, + return_type_annotation=node.return_type_annotation) + return coroutine + def visit_CFuncDefNode(self, node): - self.needs_closure = False - self.visitchildren(node) - node.needs_closure = self.needs_closure - self.needs_closure = True + self.needs_closure = False + self.visitchildren(node) + node.needs_closure = self.needs_closure + self.needs_closure = True if node.needs_closure and node.overridable: error(node.pos, "closures inside cpdef functions not yet supported") return node @@ -2652,7 +2652,7 @@ class MarkClosureVisitor(CythonTransform): self.needs_closure = True return node - + class CreateClosureClasses(CythonTransform): # Output closure classes in module scope for all functions # that really need it. @@ -2685,7 +2685,7 @@ class CreateClosureClasses(CythonTransform): if node.is_generator: for scope in node.local_scope.iter_local_scopes(): for entry in scope.entries.values(): - if not (entry.from_closure or entry.is_pyglobal or entry.is_cglobal): + if not (entry.from_closure or entry.is_pyglobal or entry.is_cglobal): entry.in_closure = True from_closure, in_closure = self.find_entries_used_in_closures(node) @@ -2718,12 +2718,12 @@ class CreateClosureClasses(CythonTransform): node.needs_outer_scope = True return - # entry.cname can contain periods (eg. a derived C method of a class). - # We want to use the cname as part of a C struct name, so we replace - # periods with double underscores. + # entry.cname can contain periods (eg. a derived C method of a class). + # We want to use the cname as part of a C struct name, so we replace + # periods with double underscores. as_name = '%s_%s' % ( target_module_scope.next_id(Naming.closure_class_prefix), - node.entry.cname.replace('.','__')) + node.entry.cname.replace('.','__')) entry = target_module_scope.declare_c_class( name=as_name, pos=node.pos, defining=True, @@ -2796,60 +2796,60 @@ class CreateClosureClasses(CythonTransform): return node -class InjectGilHandling(VisitorTransform, SkipDeclarations): - """ - Allow certain Python operations inside of nogil blocks by implicitly acquiring the GIL. - - Must run before the AnalyseDeclarationsTransform to make sure the GILStatNodes get - set up, parallel sections know that the GIL is acquired inside of them, etc. - """ - def __call__(self, root): - self.nogil = False - return super(InjectGilHandling, self).__call__(root) - - # special node handling - - def visit_RaiseStatNode(self, node): - """Allow raising exceptions in nogil sections by wrapping them in a 'with gil' block.""" - if self.nogil: - node = Nodes.GILStatNode(node.pos, state='gil', body=node) - return node - - # further candidates: - # def visit_AssertStatNode(self, node): - # def visit_ReraiseStatNode(self, node): - - # nogil tracking - - def visit_GILStatNode(self, node): - was_nogil = self.nogil - self.nogil = (node.state == 'nogil') - self.visitchildren(node) - self.nogil = was_nogil - return node - - def visit_CFuncDefNode(self, node): - was_nogil = self.nogil - if isinstance(node.declarator, Nodes.CFuncDeclaratorNode): - self.nogil = node.declarator.nogil and not node.declarator.with_gil - self.visitchildren(node) - self.nogil = was_nogil - return node - - def visit_ParallelRangeNode(self, node): - was_nogil = self.nogil - self.nogil = node.nogil - self.visitchildren(node) - self.nogil = was_nogil - return node - - def visit_ExprNode(self, node): - # No special GIL handling inside of expressions for now. - return node - - visit_Node = VisitorTransform.recurse_to_children - - +class InjectGilHandling(VisitorTransform, SkipDeclarations): + """ + Allow certain Python operations inside of nogil blocks by implicitly acquiring the GIL. + + Must run before the AnalyseDeclarationsTransform to make sure the GILStatNodes get + set up, parallel sections know that the GIL is acquired inside of them, etc. + """ + def __call__(self, root): + self.nogil = False + return super(InjectGilHandling, self).__call__(root) + + # special node handling + + def visit_RaiseStatNode(self, node): + """Allow raising exceptions in nogil sections by wrapping them in a 'with gil' block.""" + if self.nogil: + node = Nodes.GILStatNode(node.pos, state='gil', body=node) + return node + + # further candidates: + # def visit_AssertStatNode(self, node): + # def visit_ReraiseStatNode(self, node): + + # nogil tracking + + def visit_GILStatNode(self, node): + was_nogil = self.nogil + self.nogil = (node.state == 'nogil') + self.visitchildren(node) + self.nogil = was_nogil + return node + + def visit_CFuncDefNode(self, node): + was_nogil = self.nogil + if isinstance(node.declarator, Nodes.CFuncDeclaratorNode): + self.nogil = node.declarator.nogil and not node.declarator.with_gil + self.visitchildren(node) + self.nogil = was_nogil + return node + + def visit_ParallelRangeNode(self, node): + was_nogil = self.nogil + self.nogil = node.nogil + self.visitchildren(node) + self.nogil = was_nogil + return node + + def visit_ExprNode(self, node): + # No special GIL handling inside of expressions for now. + return node + + visit_Node = VisitorTransform.recurse_to_children + + class GilCheck(VisitorTransform): """ Call `node.gil_check(env)` on each node to make sure we hold the @@ -2869,28 +2869,28 @@ class GilCheck(VisitorTransform): self.nogil_declarator_only = False return super(GilCheck, self).__call__(root) - def _visit_scoped_children(self, node, gil_state): - was_nogil = self.nogil - outer_attrs = node.outer_attrs - if outer_attrs and len(self.env_stack) > 1: - self.nogil = self.env_stack[-2].nogil - self.visitchildren(node, outer_attrs) - - self.nogil = gil_state + def _visit_scoped_children(self, node, gil_state): + was_nogil = self.nogil + outer_attrs = node.outer_attrs + if outer_attrs and len(self.env_stack) > 1: + self.nogil = self.env_stack[-2].nogil + self.visitchildren(node, outer_attrs) + + self.nogil = gil_state self.visitchildren(node, attrs=None, exclude=outer_attrs) - self.nogil = was_nogil - + self.nogil = was_nogil + def visit_FuncDefNode(self, node): self.env_stack.append(node.local_scope) - inner_nogil = node.local_scope.nogil + inner_nogil = node.local_scope.nogil - if inner_nogil: + if inner_nogil: self.nogil_declarator_only = True - if inner_nogil and node.nogil_check: + if inner_nogil and node.nogil_check: node.nogil_check(node.local_scope) - self._visit_scoped_children(node, inner_nogil) + self._visit_scoped_children(node, inner_nogil) # This cannot be nested, so it doesn't need backup/restore self.nogil_declarator_only = False @@ -2903,9 +2903,9 @@ class GilCheck(VisitorTransform): node.nogil_check() was_nogil = self.nogil - is_nogil = (node.state == 'nogil') + is_nogil = (node.state == 'nogil') - if was_nogil == is_nogil and not self.nogil_declarator_only: + if was_nogil == is_nogil and not self.nogil_declarator_only: if not was_nogil: error(node.pos, "Trying to acquire the GIL while it is " "already held.") @@ -2918,7 +2918,7 @@ class GilCheck(VisitorTransform): # which is wrapped in a StatListNode. Just unpack that. node.finally_clause, = node.finally_clause.stats - self._visit_scoped_children(node, is_nogil) + self._visit_scoped_children(node, is_nogil) return node def visit_ParallelRangeNode(self, node): @@ -2965,19 +2965,19 @@ class GilCheck(VisitorTransform): def visit_Node(self, node): if self.env_stack and self.nogil and node.nogil_check: node.nogil_check(self.env_stack[-1]) - if node.outer_attrs: - self._visit_scoped_children(node, self.nogil) - else: - self.visitchildren(node) - if self.nogil: - node.in_nogil_context = True + if node.outer_attrs: + self._visit_scoped_children(node, self.nogil) + else: + self.visitchildren(node) + if self.nogil: + node.in_nogil_context = True return node class TransformBuiltinMethods(EnvTransform): - """ - Replace Cython's own cython.* builtins by the corresponding tree nodes. - """ + """ + Replace Cython's own cython.* builtins by the corresponding tree nodes. + """ def visit_SingleAssignmentNode(self, node): if node.declaration_only: @@ -3137,13 +3137,13 @@ class TransformBuiltinMethods(EnvTransform): node.function.pos, operand1=node.args[0], operand2=node.args[1]) elif function == u'cast': if len(node.args) != 2: - error(node.function.pos, - u"cast() takes exactly two arguments and an optional typecheck keyword") + error(node.function.pos, + u"cast() takes exactly two arguments and an optional typecheck keyword") else: type = node.args[0].analyse_as_type(self.current_env()) if type: - node = ExprNodes.TypecastNode( - node.function.pos, type=type, operand=node.args[1], typecheck=False) + node = ExprNodes.TypecastNode( + node.function.pos, type=type, operand=node.args[1], typecheck=False) else: error(node.args[0].pos, "Not a type") elif function == u'sizeof': @@ -3189,12 +3189,12 @@ class TransformBuiltinMethods(EnvTransform): return self._inject_super(node, func_name) return node - def visit_GeneralCallNode(self, node): - function = node.function.as_cython_attribute() + def visit_GeneralCallNode(self, node): + function = node.function.as_cython_attribute() if function == u'cast': # NOTE: assuming simple tuple/dict nodes for positional_args and keyword_args - args = node.positional_args.args - kwargs = node.keyword_args.compile_time_value(None) + args = node.positional_args.args + kwargs = node.keyword_args.compile_time_value(None) if (len(args) != 2 or len(kwargs) > 1 or (len(kwargs) == 1 and 'typecheck' not in kwargs)): error(node.function.pos, @@ -3205,13 +3205,13 @@ class TransformBuiltinMethods(EnvTransform): typecheck = kwargs.get('typecheck', False) node = ExprNodes.TypecastNode( node.function.pos, type=type, operand=args[1], typecheck=typecheck) - else: + else: error(args[0].pos, "Not a type") - self.visitchildren(node) - return node - - + self.visitchildren(node) + return node + + class ReplaceFusedTypeChecks(VisitorTransform): """ This is not a transform in the pipeline. It is invoked on the specific @@ -3348,11 +3348,11 @@ class DebugTransform(CythonTransform): self.tb.start('Globals') entries = {} - for k, v in node.scope.entries.items(): + for k, v in node.scope.entries.items(): if (v.qualified_name not in self.visited and not - v.name.startswith('__pyx_') and not - v.type.is_cfunction and not - v.type.is_extension_type): + v.name.startswith('__pyx_') and not + v.type.is_cfunction and not + v.type.is_extension_type): entries[k]= v self.serialize_local_variables(entries) @@ -3407,7 +3407,7 @@ class DebugTransform(CythonTransform): def visit_NameNode(self, node): if (self.register_stepinto and - node.type is not None and + node.type is not None and node.type.is_cfunction and getattr(node, 'is_called', False) and node.entry.func_cname is not None): diff --git a/contrib/tools/cython/Cython/Compiler/Parsing.pxd b/contrib/tools/cython/Cython/Compiler/Parsing.pxd index 8117e05c1f..25453b39ab 100644 --- a/contrib/tools/cython/Cython/Compiler/Parsing.pxd +++ b/contrib/tools/cython/Cython/Compiler/Parsing.pxd @@ -44,12 +44,12 @@ cdef p_typecast(PyrexScanner s) cdef p_sizeof(PyrexScanner s) cdef p_yield_expression(PyrexScanner s) cdef p_yield_statement(PyrexScanner s) -cdef p_async_statement(PyrexScanner s, ctx, decorators) +cdef p_async_statement(PyrexScanner s, ctx, decorators) cdef p_power(PyrexScanner s) cdef p_new_expr(PyrexScanner s) cdef p_trailer(PyrexScanner s, node1) cdef p_call_parse_args(PyrexScanner s, bint allow_genexp = *) -cdef p_call_build_packed_args(pos, positional_args, keyword_args) +cdef p_call_build_packed_args(pos, positional_args, keyword_args) cdef p_call(PyrexScanner s, function) cdef p_index(PyrexScanner s, base) cdef tuple p_subscript_list(PyrexScanner s) @@ -72,7 +72,7 @@ cdef _append_escape_sequence(kind, builder, unicode escape_sequence, PyrexScanne cdef tuple _f_string_error_pos(pos, string, Py_ssize_t i) @cython.locals(i=Py_ssize_t, size=Py_ssize_t, c=Py_UCS4, next_start=Py_ssize_t) cdef list p_f_string(PyrexScanner s, unicode_value, pos, bint is_raw) -@cython.locals(i=Py_ssize_t, size=Py_ssize_t, c=Py_UCS4, quote_char=Py_UCS4, NO_CHAR=Py_UCS4) +@cython.locals(i=Py_ssize_t, size=Py_ssize_t, c=Py_UCS4, quote_char=Py_UCS4, NO_CHAR=Py_UCS4) cdef tuple p_f_string_expr(PyrexScanner s, unicode_value, pos, Py_ssize_t starting_index, bint is_raw) cdef p_list_maker(PyrexScanner s) cdef p_comp_iter(PyrexScanner s, body) @@ -114,18 +114,18 @@ cdef p_if_statement(PyrexScanner s) cdef p_if_clause(PyrexScanner s) cdef p_else_clause(PyrexScanner s) cdef p_while_statement(PyrexScanner s) -cdef p_for_statement(PyrexScanner s, bint is_async=*) -cdef dict p_for_bounds(PyrexScanner s, bint allow_testlist=*, bint is_async=*) +cdef p_for_statement(PyrexScanner s, bint is_async=*) +cdef dict p_for_bounds(PyrexScanner s, bint allow_testlist=*, bint is_async=*) cdef p_for_from_relation(PyrexScanner s) cdef p_for_from_step(PyrexScanner s) cdef p_target(PyrexScanner s, terminator) cdef p_for_target(PyrexScanner s) -cdef p_for_iterator(PyrexScanner s, bint allow_testlist=*, bint is_async=*) +cdef p_for_iterator(PyrexScanner s, bint allow_testlist=*, bint is_async=*) cdef p_try_statement(PyrexScanner s) cdef p_except_clause(PyrexScanner s) cdef p_include_statement(PyrexScanner s, ctx) cdef p_with_statement(PyrexScanner s) -cdef p_with_items(PyrexScanner s, bint is_async=*) +cdef p_with_items(PyrexScanner s, bint is_async=*) cdef p_with_template(PyrexScanner s) cdef p_simple_statement(PyrexScanner s, bint first_statement = *) cdef p_simple_statement_list(PyrexScanner s, ctx, bint first_statement = *) @@ -135,7 +135,7 @@ cdef p_IF_statement(PyrexScanner s, ctx) cdef p_statement(PyrexScanner s, ctx, bint first_statement = *) cdef p_statement_list(PyrexScanner s, ctx, bint first_statement = *) cdef p_suite(PyrexScanner s, ctx = *) -cdef tuple p_suite_with_docstring(PyrexScanner s, ctx, bint with_doc_only=*) +cdef tuple p_suite_with_docstring(PyrexScanner s, ctx, bint with_doc_only=*) cdef tuple _extract_docstring(node) cdef p_positional_and_keyword_args(PyrexScanner s, end_sy_set, templates = *) @@ -183,17 +183,17 @@ cdef p_c_modifiers(PyrexScanner s) cdef p_c_func_or_var_declaration(PyrexScanner s, pos, ctx) cdef p_ctypedef_statement(PyrexScanner s, ctx) cdef p_decorators(PyrexScanner s) -cdef _reject_cdef_modifier_in_py(PyrexScanner s, name) -cdef p_def_statement(PyrexScanner s, list decorators=*, bint is_async_def=*) +cdef _reject_cdef_modifier_in_py(PyrexScanner s, name) +cdef p_def_statement(PyrexScanner s, list decorators=*, bint is_async_def=*) cdef p_varargslist(PyrexScanner s, terminator=*, bint annotated = *) cdef p_py_arg_decl(PyrexScanner s, bint annotated = *) cdef p_class_statement(PyrexScanner s, decorators) cdef p_c_class_definition(PyrexScanner s, pos, ctx) -cdef tuple p_c_class_options(PyrexScanner s) +cdef tuple p_c_class_options(PyrexScanner s) cdef p_property_decl(PyrexScanner s) cdef p_doc_string(PyrexScanner s) cdef p_ignorable_statement(PyrexScanner s) -cdef dict p_compiler_directive_comments(PyrexScanner s) -cdef p_template_definition(PyrexScanner s) +cdef dict p_compiler_directive_comments(PyrexScanner s) +cdef p_template_definition(PyrexScanner s) cdef p_cpp_class_definition(PyrexScanner s, pos, ctx) cdef p_cpp_class_attribute(PyrexScanner s, ctx) diff --git a/contrib/tools/cython/Cython/Compiler/Parsing.py b/contrib/tools/cython/Cython/Compiler/Parsing.py index 14110fcc06..4d2f12a24a 100644 --- a/contrib/tools/cython/Cython/Compiler/Parsing.py +++ b/contrib/tools/cython/Cython/Compiler/Parsing.py @@ -8,37 +8,37 @@ from __future__ import absolute_import # This should be done automatically import cython cython.declare(Nodes=object, ExprNodes=object, EncodedString=object, - bytes_literal=object, StringEncoding=object, + bytes_literal=object, StringEncoding=object, FileSourceDescriptor=object, lookup_unicodechar=object, unicode_category=object, Future=object, Options=object, error=object, warning=object, Builtin=object, ModuleNode=object, Utils=object, _unicode=object, _bytes=object, re=object, sys=object, _parse_escape_sequences=object, _parse_escape_sequences_raw=object, - partial=object, reduce=object, _IS_PY3=cython.bint, _IS_2BYTE_UNICODE=cython.bint, - _CDEF_MODIFIERS=tuple) + partial=object, reduce=object, _IS_PY3=cython.bint, _IS_2BYTE_UNICODE=cython.bint, + _CDEF_MODIFIERS=tuple) -from io import StringIO +from io import StringIO import re -import sys +import sys from unicodedata import lookup as lookup_unicodechar, category as unicode_category -from functools import partial, reduce +from functools import partial, reduce -from .Scanning import PyrexScanner, FileSourceDescriptor, StringSourceDescriptor +from .Scanning import PyrexScanner, FileSourceDescriptor, StringSourceDescriptor from . import Nodes from . import ExprNodes from . import Builtin from . import StringEncoding -from .StringEncoding import EncodedString, bytes_literal, _unicode, _bytes +from .StringEncoding import EncodedString, bytes_literal, _unicode, _bytes from .ModuleNode import ModuleNode from .Errors import error, warning from .. import Utils from . import Future from . import Options -_IS_PY3 = sys.version_info[0] >= 3 +_IS_PY3 = sys.version_info[0] >= 3 _IS_2BYTE_UNICODE = sys.maxunicode == 0xffff -_CDEF_MODIFIERS = ('inline', 'nogil', 'api') +_CDEF_MODIFIERS = ('inline', 'nogil', 'api') + - class Ctx(object): # Parsing context level = 'other' @@ -62,8 +62,8 @@ class Ctx(object): d.update(kwds) return ctx - -def p_ident(s, message="Expected an identifier"): + +def p_ident(s, message="Expected an identifier"): if s.sy == 'IDENT': name = s.systring s.next() @@ -218,7 +218,7 @@ def p_starred_expr(s): starred = False expr = p_bit_expr(s) if starred: - expr = ExprNodes.StarredUnpackingNode(pos, expr) + expr = ExprNodes.StarredUnpackingNode(pos, expr) return expr def p_cascaded_cmp(s): @@ -358,7 +358,7 @@ def p_sizeof(s): s.expect(')') return node - + def p_yield_expression(s): # s.sy == "yield" pos = s.position() @@ -368,8 +368,8 @@ def p_yield_expression(s): is_yield_from = True s.next() if s.sy != ')' and s.sy not in statement_terminators: - # "yield from" does not support implicit tuples, but "yield" does ("yield 1,2") - arg = p_test(s) if is_yield_from else p_testlist(s) + # "yield from" does not support implicit tuples, but "yield" does ("yield 1,2") + arg = p_test(s) if is_yield_from else p_testlist(s) else: if is_yield_from: s.error("'yield from' requires a source argument", @@ -380,47 +380,47 @@ def p_yield_expression(s): else: return ExprNodes.YieldExprNode(pos, arg=arg) - + def p_yield_statement(s): # s.sy == "yield" yield_expr = p_yield_expression(s) return Nodes.ExprStatNode(yield_expr.pos, expr=yield_expr) -def p_async_statement(s, ctx, decorators): - # s.sy >> 'async' ... - if s.sy == 'def': - # 'async def' statements aren't allowed in pxd files - if 'pxd' in ctx.level: - s.error('def statement not allowed here') - s.level = ctx.level - return p_def_statement(s, decorators, is_async_def=True) - elif decorators: - s.error("Decorators can only be followed by functions or classes") - elif s.sy == 'for': - return p_for_statement(s, is_async=True) - elif s.sy == 'with': - s.next() - return p_with_items(s, is_async=True) - else: - s.error("expected one of 'def', 'for', 'with' after 'async'") - - -#power: atom_expr ('**' factor)* -#atom_expr: ['await'] atom trailer* - +def p_async_statement(s, ctx, decorators): + # s.sy >> 'async' ... + if s.sy == 'def': + # 'async def' statements aren't allowed in pxd files + if 'pxd' in ctx.level: + s.error('def statement not allowed here') + s.level = ctx.level + return p_def_statement(s, decorators, is_async_def=True) + elif decorators: + s.error("Decorators can only be followed by functions or classes") + elif s.sy == 'for': + return p_for_statement(s, is_async=True) + elif s.sy == 'with': + s.next() + return p_with_items(s, is_async=True) + else: + s.error("expected one of 'def', 'for', 'with' after 'async'") + + +#power: atom_expr ('**' factor)* +#atom_expr: ['await'] atom trailer* + def p_power(s): if s.systring == 'new' and s.peek()[0] == 'IDENT': return p_new_expr(s) - await_pos = None - if s.sy == 'await': - await_pos = s.position() - s.next() + await_pos = None + if s.sy == 'await': + await_pos = s.position() + s.next() n1 = p_atom(s) while s.sy in ('(', '[', '.'): n1 = p_trailer(s, n1) - if await_pos: - n1 = ExprNodes.AwaitExprNode(await_pos, arg=n1) + if await_pos: + n1 = ExprNodes.AwaitExprNode(await_pos, arg=n1) if s.sy == '**': pos = s.position() s.next() @@ -428,7 +428,7 @@ def p_power(s): n1 = ExprNodes.binop_node(pos, '**', n1, n2) return n1 - + def p_new_expr(s): # s.systring == 'new'. pos = s.position() @@ -446,39 +446,39 @@ def p_trailer(s, node1): return p_index(s, node1) else: # s.sy == '.' s.next() - name = p_ident(s) + name = p_ident(s) return ExprNodes.AttributeNode(pos, - obj=node1, attribute=name) + obj=node1, attribute=name) + - # arglist: argument (',' argument)* [','] # argument: [test '='] test # Really [keyword '='] test -# since PEP 448: -# argument: ( test [comp_for] | -# test '=' test | -# '**' expr | -# star_expr ) - -def p_call_parse_args(s, allow_genexp=True): +# since PEP 448: +# argument: ( test [comp_for] | +# test '=' test | +# '**' expr | +# star_expr ) + +def p_call_parse_args(s, allow_genexp=True): # s.sy == '(' pos = s.position() s.next() positional_args = [] keyword_args = [] - starstar_seen = False - last_was_tuple_unpack = False - while s.sy != ')': + starstar_seen = False + last_was_tuple_unpack = False + while s.sy != ')': if s.sy == '*': - if starstar_seen: - s.error("Non-keyword arg following keyword arg", pos=s.position()) + if starstar_seen: + s.error("Non-keyword arg following keyword arg", pos=s.position()) + s.next() + positional_args.append(p_test(s)) + last_was_tuple_unpack = True + elif s.sy == '**': s.next() - positional_args.append(p_test(s)) - last_was_tuple_unpack = True - elif s.sy == '**': - s.next() - keyword_args.append(p_test(s)) - starstar_seen = True + keyword_args.append(p_test(s)) + starstar_seen = True else: arg = p_test(s) if s.sy == '=': @@ -486,86 +486,86 @@ def p_call_parse_args(s, allow_genexp=True): if not arg.is_name: s.error("Expected an identifier before '='", pos=arg.pos) - encoded_name = s.context.intern_ustring(arg.name) + encoded_name = s.context.intern_ustring(arg.name) keyword = ExprNodes.IdentifierStringNode( arg.pos, value=encoded_name) arg = p_test(s) keyword_args.append((keyword, arg)) else: if keyword_args: - s.error("Non-keyword arg following keyword arg", pos=arg.pos) - if positional_args and not last_was_tuple_unpack: - positional_args[-1].append(arg) - else: - positional_args.append([arg]) - last_was_tuple_unpack = False + s.error("Non-keyword arg following keyword arg", pos=arg.pos) + if positional_args and not last_was_tuple_unpack: + positional_args[-1].append(arg) + else: + positional_args.append([arg]) + last_was_tuple_unpack = False if s.sy != ',': break s.next() if s.sy in ('for', 'async'): - if not keyword_args and not last_was_tuple_unpack: - if len(positional_args) == 1 and len(positional_args[0]) == 1: - positional_args = [[p_genexp(s, positional_args[0][0])]] + if not keyword_args and not last_was_tuple_unpack: + if len(positional_args) == 1 and len(positional_args[0]) == 1: + positional_args = [[p_genexp(s, positional_args[0][0])]] s.expect(')') - return positional_args or [[]], keyword_args + return positional_args or [[]], keyword_args + - -def p_call_build_packed_args(pos, positional_args, keyword_args): +def p_call_build_packed_args(pos, positional_args, keyword_args): keyword_dict = None - - subtuples = [ - ExprNodes.TupleNode(pos, args=arg) if isinstance(arg, list) else ExprNodes.AsTupleNode(pos, arg=arg) - for arg in positional_args - ] - # TODO: implement a faster way to join tuples than creating each one and adding them - arg_tuple = reduce(partial(ExprNodes.binop_node, pos, '+'), subtuples) - - if keyword_args: - kwargs = [] - dict_items = [] - for item in keyword_args: - if isinstance(item, tuple): - key, value = item - dict_items.append(ExprNodes.DictItemNode(pos=key.pos, key=key, value=value)) - elif item.is_dict_literal: - # unpack "**{a:b}" directly - dict_items.extend(item.key_value_pairs) - else: - if dict_items: - kwargs.append(ExprNodes.DictNode( - dict_items[0].pos, key_value_pairs=dict_items, reject_duplicates=True)) - dict_items = [] - kwargs.append(item) - - if dict_items: - kwargs.append(ExprNodes.DictNode( - dict_items[0].pos, key_value_pairs=dict_items, reject_duplicates=True)) - - if kwargs: - if len(kwargs) == 1 and kwargs[0].is_dict_literal: - # only simple keyword arguments found -> one dict - keyword_dict = kwargs[0] - else: - # at least one **kwargs - keyword_dict = ExprNodes.MergedDictNode(pos, keyword_args=kwargs) - + + subtuples = [ + ExprNodes.TupleNode(pos, args=arg) if isinstance(arg, list) else ExprNodes.AsTupleNode(pos, arg=arg) + for arg in positional_args + ] + # TODO: implement a faster way to join tuples than creating each one and adding them + arg_tuple = reduce(partial(ExprNodes.binop_node, pos, '+'), subtuples) + + if keyword_args: + kwargs = [] + dict_items = [] + for item in keyword_args: + if isinstance(item, tuple): + key, value = item + dict_items.append(ExprNodes.DictItemNode(pos=key.pos, key=key, value=value)) + elif item.is_dict_literal: + # unpack "**{a:b}" directly + dict_items.extend(item.key_value_pairs) + else: + if dict_items: + kwargs.append(ExprNodes.DictNode( + dict_items[0].pos, key_value_pairs=dict_items, reject_duplicates=True)) + dict_items = [] + kwargs.append(item) + + if dict_items: + kwargs.append(ExprNodes.DictNode( + dict_items[0].pos, key_value_pairs=dict_items, reject_duplicates=True)) + + if kwargs: + if len(kwargs) == 1 and kwargs[0].is_dict_literal: + # only simple keyword arguments found -> one dict + keyword_dict = kwargs[0] + else: + # at least one **kwargs + keyword_dict = ExprNodes.MergedDictNode(pos, keyword_args=kwargs) + return arg_tuple, keyword_dict - + def p_call(s, function): # s.sy == '(' pos = s.position() - positional_args, keyword_args = p_call_parse_args(s) + positional_args, keyword_args = p_call_parse_args(s) - if not keyword_args and len(positional_args) == 1 and isinstance(positional_args[0], list): - return ExprNodes.SimpleCallNode(pos, function=function, args=positional_args[0]) + if not keyword_args and len(positional_args) == 1 and isinstance(positional_args[0], list): + return ExprNodes.SimpleCallNode(pos, function=function, args=positional_args[0]) else: - arg_tuple, keyword_dict = p_call_build_packed_args(pos, positional_args, keyword_args) - return ExprNodes.GeneralCallNode( - pos, function=function, positional_args=arg_tuple, keyword_args=keyword_dict) + arg_tuple, keyword_dict = p_call_build_packed_args(pos, positional_args, keyword_args) + return ExprNodes.GeneralCallNode( + pos, function=function, positional_args=arg_tuple, keyword_args=keyword_dict) + - #lambdef: 'lambda' [varargslist] ':' test #subscriptlist: subscript (',' subscript)* [','] @@ -697,14 +697,14 @@ def p_atom(s): return ExprNodes.UnicodeNode(pos, value = unicode_value, bytes_value = bytes_value) elif kind == 'b': return ExprNodes.BytesNode(pos, value = bytes_value) - elif kind == 'f': - return ExprNodes.JoinedStrNode(pos, values = unicode_value) - elif kind == '': - return ExprNodes.StringNode(pos, value = bytes_value, unicode_value = unicode_value) + elif kind == 'f': + return ExprNodes.JoinedStrNode(pos, values = unicode_value) + elif kind == '': + return ExprNodes.StringNode(pos, value = bytes_value, unicode_value = unicode_value) else: - s.error("invalid string kind '%s'" % kind) + s.error("invalid string kind '%s'" % kind) elif sy == 'IDENT': - name = s.systring + name = s.systring if name == "None": result = ExprNodes.NoneNode(pos) elif name == "True": @@ -771,9 +771,9 @@ def wrap_compile_time_constant(pos, value): elif isinstance(value, bool): return ExprNodes.BoolNode(pos, value=value) elif isinstance(value, int): - return ExprNodes.IntNode(pos, value=rep, constant_result=value) + return ExprNodes.IntNode(pos, value=rep, constant_result=value) elif isinstance(value, float): - return ExprNodes.FloatNode(pos, value=rep, constant_result=value) + return ExprNodes.FloatNode(pos, value=rep, constant_result=value) elif isinstance(value, complex): node = ExprNodes.ImagNode(pos, value=repr(value.imag), constant_result=complex(0.0, value.imag)) if value.real: @@ -786,8 +786,8 @@ def wrap_compile_time_constant(pos, value): elif isinstance(value, _unicode): return ExprNodes.UnicodeNode(pos, value=EncodedString(value)) elif isinstance(value, _bytes): - bvalue = bytes_literal(value, 'ascii') # actually: unknown encoding, but BytesLiteral requires one - return ExprNodes.BytesNode(pos, value=bvalue, constant_result=value) + bvalue = bytes_literal(value, 'ascii') # actually: unknown encoding, but BytesLiteral requires one + return ExprNodes.BytesNode(pos, value=bvalue, constant_result=value) elif isinstance(value, tuple): args = [wrap_compile_time_constant(pos, arg) for arg in value] @@ -796,8 +796,8 @@ def wrap_compile_time_constant(pos, value): else: # error already reported return None - elif not _IS_PY3 and isinstance(value, long): - return ExprNodes.IntNode(pos, value=rep.rstrip('L'), constant_result=value) + elif not _IS_PY3 and isinstance(value, long): + return ExprNodes.IntNode(pos, value=rep.rstrip('L'), constant_result=value) error(pos, "Invalid type for compile-time constant: %r (type %s)" % (value, value.__class__.__name__)) return None @@ -806,84 +806,84 @@ def wrap_compile_time_constant(pos, value): def p_cat_string_literal(s): # A sequence of one or more adjacent string literals. # Returns (kind, bytes_value, unicode_value) - # where kind in ('b', 'c', 'u', 'f', '') - pos = s.position() + # where kind in ('b', 'c', 'u', 'f', '') + pos = s.position() kind, bytes_value, unicode_value = p_string_literal(s) if kind == 'c' or s.sy != 'BEGIN_STRING': return kind, bytes_value, unicode_value - bstrings, ustrings, positions = [bytes_value], [unicode_value], [pos] + bstrings, ustrings, positions = [bytes_value], [unicode_value], [pos] bytes_value = unicode_value = None while s.sy == 'BEGIN_STRING': pos = s.position() next_kind, next_bytes_value, next_unicode_value = p_string_literal(s) if next_kind == 'c': error(pos, "Cannot concatenate char literal with another string or char literal") - continue + continue elif next_kind != kind: - # concatenating f strings and normal strings is allowed and leads to an f string - if set([kind, next_kind]) in (set(['f', 'u']), set(['f', ''])): - kind = 'f' - else: + # concatenating f strings and normal strings is allowed and leads to an f string + if set([kind, next_kind]) in (set(['f', 'u']), set(['f', ''])): + kind = 'f' + else: error(pos, "Cannot mix string literals of different types, expected %s'', got %s''" % ( kind, next_kind)) - continue - bstrings.append(next_bytes_value) - ustrings.append(next_unicode_value) - positions.append(pos) + continue + bstrings.append(next_bytes_value) + ustrings.append(next_unicode_value) + positions.append(pos) # join and rewrap the partial literals if kind in ('b', 'c', '') or kind == 'u' and None not in bstrings: # Py3 enforced unicode literals are parsed as bytes/unicode combination - bytes_value = bytes_literal(StringEncoding.join_bytes(bstrings), s.source_encoding) + bytes_value = bytes_literal(StringEncoding.join_bytes(bstrings), s.source_encoding) if kind in ('u', ''): - unicode_value = EncodedString(u''.join([u for u in ustrings if u is not None])) - if kind == 'f': - unicode_value = [] - for u, pos in zip(ustrings, positions): - if isinstance(u, list): - unicode_value += u - else: - # non-f-string concatenated into the f-string - unicode_value.append(ExprNodes.UnicodeNode(pos, value=EncodedString(u))) + unicode_value = EncodedString(u''.join([u for u in ustrings if u is not None])) + if kind == 'f': + unicode_value = [] + for u, pos in zip(ustrings, positions): + if isinstance(u, list): + unicode_value += u + else: + # non-f-string concatenated into the f-string + unicode_value.append(ExprNodes.UnicodeNode(pos, value=EncodedString(u))) return kind, bytes_value, unicode_value - + def p_opt_string_literal(s, required_type='u'): - if s.sy != 'BEGIN_STRING': - return None - pos = s.position() - kind, bytes_value, unicode_value = p_string_literal(s, required_type) - if required_type == 'u': - if kind == 'f': - s.error("f-string not allowed here", pos) - return unicode_value - elif required_type == 'b': - return bytes_value - else: - s.error("internal parser configuration error") - - + if s.sy != 'BEGIN_STRING': + return None + pos = s.position() + kind, bytes_value, unicode_value = p_string_literal(s, required_type) + if required_type == 'u': + if kind == 'f': + s.error("f-string not allowed here", pos) + return unicode_value + elif required_type == 'b': + return bytes_value + else: + s.error("internal parser configuration error") + + def check_for_non_ascii_characters(string): for c in string: if c >= u'\x80': return True return False - + def p_string_literal(s, kind_override=None): # A single string or char literal. Returns (kind, bvalue, uvalue) - # where kind in ('b', 'c', 'u', 'f', ''). The 'bvalue' is the source + # where kind in ('b', 'c', 'u', 'f', ''). The 'bvalue' is the source # code byte sequence of the string literal, 'uvalue' is the # decoded Unicode string. Either of the two may be None depending # on the 'kind' of string, only unprefixed strings have both - # representations. In f-strings, the uvalue is a list of the Unicode - # strings and f-string expressions that make up the f-string. + # representations. In f-strings, the uvalue is a list of the Unicode + # strings and f-string expressions that make up the f-string. # s.sy == 'BEGIN_STRING' pos = s.position() is_python3_source = s.context.language_level >= 3 - has_non_ascii_literal_characters = False + has_non_ascii_literal_characters = False string_start_pos = (pos[0], pos[1], pos[2] + len(s.systring)) - kind_string = s.systring.rstrip('"\'').lower() + kind_string = s.systring.rstrip('"\'').lower() if len(kind_string) > 1: if len(set(kind_string)) != len(kind_string): error(pos, 'Duplicate string prefix character') @@ -893,32 +893,32 @@ def p_string_literal(s, kind_override=None): error(pos, 'String prefixes b and f cannot be combined') if 'u' in kind_string and 'f' in kind_string: error(pos, 'String prefixes u and f cannot be combined') - - is_raw = 'r' in kind_string - - if 'c' in kind_string: - # this should never happen, since the lexer does not allow combining c - # with other prefix characters - if len(kind_string) != 1: + + is_raw = 'r' in kind_string + + if 'c' in kind_string: + # this should never happen, since the lexer does not allow combining c + # with other prefix characters + if len(kind_string) != 1: error(pos, 'Invalid string prefix for character literal') - kind = 'c' - elif 'f' in kind_string: + kind = 'c' + elif 'f' in kind_string: kind = 'f' # u is ignored is_raw = True # postpone the escape resolution - elif 'b' in kind_string: - kind = 'b' - elif 'u' in kind_string: - kind = 'u' - else: + elif 'b' in kind_string: + kind = 'b' + elif 'u' in kind_string: + kind = 'u' + else: kind = '' - + if kind == '' and kind_override is None and Future.unicode_literals in s.context.future_directives: chars = StringEncoding.StrLiteralBuilder(s.source_encoding) kind = 'u' else: if kind_override is not None and kind_override in 'ub': kind = kind_override - if kind in ('u', 'f'): # f-strings are scanned exactly like Unicode literals, but are parsed further later + if kind in ('u', 'f'): # f-strings are scanned exactly like Unicode literals, but are parsed further later chars = StringEncoding.UnicodeLiteralBuilder() elif kind == '': chars = StringEncoding.StrLiteralBuilder(s.source_encoding) @@ -929,17 +929,17 @@ def p_string_literal(s, kind_override=None): s.next() sy = s.sy systr = s.systring - # print "p_string_literal: sy =", sy, repr(s.systring) ### + # print "p_string_literal: sy =", sy, repr(s.systring) ### if sy == 'CHARS': chars.append(systr) - if is_python3_source and not has_non_ascii_literal_characters and check_for_non_ascii_characters(systr): - has_non_ascii_literal_characters = True + if is_python3_source and not has_non_ascii_literal_characters and check_for_non_ascii_characters(systr): + has_non_ascii_literal_characters = True elif sy == 'ESCAPE': # in Py2, 'ur' raw unicode strings resolve unicode escapes but nothing else if is_raw and (is_python3_source or kind != 'u' or systr[1] not in u'Uu'): chars.append(systr) if is_python3_source and not has_non_ascii_literal_characters and check_for_non_ascii_characters(systr): - has_non_ascii_literal_characters = True + has_non_ascii_literal_characters = True else: _append_escape_sequence(kind, chars, systr, s) elif sy == 'NEWLINE': @@ -959,18 +959,18 @@ def p_string_literal(s, kind_override=None): error(pos, u"invalid character literal: %r" % bytes_value) else: bytes_value, unicode_value = chars.getstrings() - if (has_non_ascii_literal_characters - and is_python3_source and Future.unicode_literals in s.context.future_directives): + if (has_non_ascii_literal_characters + and is_python3_source and Future.unicode_literals in s.context.future_directives): # Python 3 forbids literal non-ASCII characters in byte strings - if kind == 'b': + if kind == 'b': s.error("bytes can only contain ASCII literal characters.", pos=pos) bytes_value = None - if kind == 'f': + if kind == 'f': unicode_value = p_f_string(s, unicode_value, string_start_pos, is_raw='r' in kind_string) s.next() return (kind, bytes_value, unicode_value) - + def _append_escape_sequence(kind, builder, escape_sequence, s): c = escape_sequence[1] if c in u"01234567": @@ -1043,11 +1043,11 @@ def _f_string_error_pos(pos, string, i): def p_f_string(s, unicode_value, pos, is_raw): - # Parses a PEP 498 f-string literal into a list of nodes. Nodes are either UnicodeNodes - # or FormattedValueNodes. - values = [] + # Parses a PEP 498 f-string literal into a list of nodes. Nodes are either UnicodeNodes + # or FormattedValueNodes. + values = [] next_start = 0 - size = len(unicode_value) + size = len(unicode_value) builder = StringEncoding.UnicodeLiteralBuilder() _parse_seq = _parse_escape_sequences_raw if is_raw else _parse_escape_sequences @@ -1063,7 +1063,7 @@ def p_f_string(s, unicode_value, pos, is_raw): if c == '\\': if not is_raw and len(part) > 1: _append_escape_sequence('f', builder, part, s) - else: + else: builder.append(part) elif c == '{': if part == '{{': @@ -1074,150 +1074,150 @@ def p_f_string(s, unicode_value, pos, is_raw): values.append(ExprNodes.UnicodeNode(pos, value=builder.getstring())) builder = StringEncoding.UnicodeLiteralBuilder() next_start, expr_node = p_f_string_expr(s, unicode_value, pos, next_start, is_raw) - values.append(expr_node) + values.append(expr_node) elif c == '}': if part == '}}': builder.append('}') else: error(_f_string_error_pos(pos, unicode_value, end), "f-string: single '}' is not allowed") - else: + else: builder.append(part) - + if builder.chars: values.append(ExprNodes.UnicodeNode(pos, value=builder.getstring())) - return values - - + return values + + def p_f_string_expr(s, unicode_value, pos, starting_index, is_raw): - # Parses a {}-delimited expression inside an f-string. Returns a FormattedValueNode - # and the index in the string that follows the expression. - i = starting_index - size = len(unicode_value) - conversion_char = terminal_char = format_spec = None - format_spec_str = None - NO_CHAR = 2**30 - - nested_depth = 0 - quote_char = NO_CHAR - in_triple_quotes = False + # Parses a {}-delimited expression inside an f-string. Returns a FormattedValueNode + # and the index in the string that follows the expression. + i = starting_index + size = len(unicode_value) + conversion_char = terminal_char = format_spec = None + format_spec_str = None + NO_CHAR = 2**30 + + nested_depth = 0 + quote_char = NO_CHAR + in_triple_quotes = False backslash_reported = False - - while True: - if i >= size: + + while True: + if i >= size: break # error will be reported below - c = unicode_value[i] - - if quote_char != NO_CHAR: - if c == '\\': + c = unicode_value[i] + + if quote_char != NO_CHAR: + if c == '\\': # avoid redundant error reports along '\' sequences if not backslash_reported: error(_f_string_error_pos(pos, unicode_value, i), "backslashes not allowed in f-strings") backslash_reported = True - elif c == quote_char: - if in_triple_quotes: - if i + 2 < size and unicode_value[i + 1] == c and unicode_value[i + 2] == c: - in_triple_quotes = False - quote_char = NO_CHAR - i += 2 - else: - quote_char = NO_CHAR - elif c in '\'"': - quote_char = c - if i + 2 < size and unicode_value[i + 1] == c and unicode_value[i + 2] == c: - in_triple_quotes = True - i += 2 - elif c in '{[(': - nested_depth += 1 - elif nested_depth != 0 and c in '}])': - nested_depth -= 1 - elif c == '#': + elif c == quote_char: + if in_triple_quotes: + if i + 2 < size and unicode_value[i + 1] == c and unicode_value[i + 2] == c: + in_triple_quotes = False + quote_char = NO_CHAR + i += 2 + else: + quote_char = NO_CHAR + elif c in '\'"': + quote_char = c + if i + 2 < size and unicode_value[i + 1] == c and unicode_value[i + 2] == c: + in_triple_quotes = True + i += 2 + elif c in '{[(': + nested_depth += 1 + elif nested_depth != 0 and c in '}])': + nested_depth -= 1 + elif c == '#': error(_f_string_error_pos(pos, unicode_value, i), "format string cannot include #") - elif nested_depth == 0 and c in '!:}': - # allow != as a special case - if c == '!' and i + 1 < size and unicode_value[i + 1] == '=': - i += 1 - continue - - terminal_char = c - break - i += 1 - - # normalise line endings as the parser expects that - expr_str = unicode_value[starting_index:i].replace('\r\n', '\n').replace('\r', '\n') - expr_pos = (pos[0], pos[1], pos[2] + starting_index + 2) # TODO: find exact code position (concat, multi-line, ...) - - if not expr_str.strip(): + elif nested_depth == 0 and c in '!:}': + # allow != as a special case + if c == '!' and i + 1 < size and unicode_value[i + 1] == '=': + i += 1 + continue + + terminal_char = c + break + i += 1 + + # normalise line endings as the parser expects that + expr_str = unicode_value[starting_index:i].replace('\r\n', '\n').replace('\r', '\n') + expr_pos = (pos[0], pos[1], pos[2] + starting_index + 2) # TODO: find exact code position (concat, multi-line, ...) + + if not expr_str.strip(): error(_f_string_error_pos(pos, unicode_value, starting_index), "empty expression not allowed in f-string") - - if terminal_char == '!': - i += 1 - if i + 2 > size: + + if terminal_char == '!': + i += 1 + if i + 2 > size: pass # error will be reported below else: conversion_char = unicode_value[i] i += 1 terminal_char = unicode_value[i] - - if terminal_char == ':': - in_triple_quotes = False - in_string = False - nested_depth = 0 - start_format_spec = i + 1 - while True: - if i >= size: + + if terminal_char == ':': + in_triple_quotes = False + in_string = False + nested_depth = 0 + start_format_spec = i + 1 + while True: + if i >= size: break # error will be reported below - c = unicode_value[i] - if not in_triple_quotes and not in_string: - if c == '{': - nested_depth += 1 - elif c == '}': - if nested_depth > 0: - nested_depth -= 1 - else: - terminal_char = c - break - if c in '\'"': - if not in_string and i + 2 < size and unicode_value[i + 1] == c and unicode_value[i + 2] == c: - in_triple_quotes = not in_triple_quotes - i += 2 - elif not in_triple_quotes: - in_string = not in_string - i += 1 - - format_spec_str = unicode_value[start_format_spec:i] - - if terminal_char != '}': + c = unicode_value[i] + if not in_triple_quotes and not in_string: + if c == '{': + nested_depth += 1 + elif c == '}': + if nested_depth > 0: + nested_depth -= 1 + else: + terminal_char = c + break + if c in '\'"': + if not in_string and i + 2 < size and unicode_value[i + 1] == c and unicode_value[i + 2] == c: + in_triple_quotes = not in_triple_quotes + i += 2 + elif not in_triple_quotes: + in_string = not in_string + i += 1 + + format_spec_str = unicode_value[start_format_spec:i] + + if terminal_char != '}': error(_f_string_error_pos(pos, unicode_value, i), "missing '}' in format string expression" + ( ", found '%s'" % terminal_char if terminal_char else "")) - - # parse the expression as if it was surrounded by parentheses - buf = StringIO('(%s)' % expr_str) - scanner = PyrexScanner(buf, expr_pos[0], parent_scanner=s, source_encoding=s.source_encoding, initial_pos=expr_pos) - expr = p_testlist(scanner) # TODO is testlist right here? - - # validate the conversion char - if conversion_char is not None and not ExprNodes.FormattedValueNode.find_conversion_func(conversion_char): + + # parse the expression as if it was surrounded by parentheses + buf = StringIO('(%s)' % expr_str) + scanner = PyrexScanner(buf, expr_pos[0], parent_scanner=s, source_encoding=s.source_encoding, initial_pos=expr_pos) + expr = p_testlist(scanner) # TODO is testlist right here? + + # validate the conversion char + if conversion_char is not None and not ExprNodes.FormattedValueNode.find_conversion_func(conversion_char): error(expr_pos, "invalid conversion character '%s'" % conversion_char) - - # the format spec is itself treated like an f-string - if format_spec_str: + + # the format spec is itself treated like an f-string + if format_spec_str: format_spec = ExprNodes.JoinedStrNode(pos, values=p_f_string(s, format_spec_str, pos, is_raw)) - - return i + 1, ExprNodes.FormattedValueNode( + + return i + 1, ExprNodes.FormattedValueNode( pos, value=expr, conversion_char=conversion_char, format_spec=format_spec) - - -# since PEP 448: -# list_display ::= "[" [listmaker] "]" -# listmaker ::= (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] ) + + +# since PEP 448: +# list_display ::= "[" [listmaker] "]" +# listmaker ::= (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] ) # comp_iter ::= comp_for | comp_if # comp_for ::= ["async"] "for" expression_list "in" testlist [comp_iter] -# comp_if ::= "if" test [comp_iter] +# comp_if ::= "if" test [comp_iter] def p_list_maker(s): # s.sy == '[' @@ -1225,30 +1225,30 @@ def p_list_maker(s): s.next() if s.sy == ']': s.expect(']') - return ExprNodes.ListNode(pos, args=[]) - - expr = p_test_or_starred_expr(s) + return ExprNodes.ListNode(pos, args=[]) + + expr = p_test_or_starred_expr(s) if s.sy in ('for', 'async'): - if expr.is_starred: - s.error("iterable unpacking cannot be used in comprehension") + if expr.is_starred: + s.error("iterable unpacking cannot be used in comprehension") append = ExprNodes.ComprehensionAppendNode(pos, expr=expr) loop = p_comp_for(s, append) s.expect(']') return ExprNodes.ComprehensionNode( - pos, loop=loop, append=append, type=Builtin.list_type, + pos, loop=loop, append=append, type=Builtin.list_type, # list comprehensions leak their loop variable in Py2 - has_local_scope=s.context.language_level >= 3) - - # (merged) list literal - if s.sy == ',': - s.next() - exprs = p_test_or_starred_expr_list(s, expr) - else: - exprs = [expr] - s.expect(']') - return ExprNodes.ListNode(pos, args=exprs) - - + has_local_scope=s.context.language_level >= 3) + + # (merged) list literal + if s.sy == ',': + s.next() + exprs = p_test_or_starred_expr_list(s, expr) + else: + exprs = [expr] + s.expect(']') + return ExprNodes.ListNode(pos, args=exprs) + + def p_comp_iter(s, body): if s.sy in ('for', 'async'): return p_comp_for(s, body) @@ -1283,121 +1283,121 @@ def p_comp_if(s, body): else_clause = None ) -# since PEP 448: -#dictorsetmaker: ( ((test ':' test | '**' expr) -# (comp_for | (',' (test ':' test | '**' expr))* [','])) | -# ((test | star_expr) -# (comp_for | (',' (test | star_expr))* [','])) ) - +# since PEP 448: +#dictorsetmaker: ( ((test ':' test | '**' expr) +# (comp_for | (',' (test ':' test | '**' expr))* [','])) | +# ((test | star_expr) +# (comp_for | (',' (test | star_expr))* [','])) ) + def p_dict_or_set_maker(s): # s.sy == '{' pos = s.position() s.next() if s.sy == '}': s.next() - return ExprNodes.DictNode(pos, key_value_pairs=[]) - - parts = [] - target_type = 0 - last_was_simple_item = False - while True: - if s.sy in ('*', '**'): - # merged set/dict literal - if target_type == 0: - target_type = 1 if s.sy == '*' else 2 # 'stars' - elif target_type != len(s.sy): - s.error("unexpected %sitem found in %s literal" % ( - s.sy, 'set' if target_type == 1 else 'dict')) + return ExprNodes.DictNode(pos, key_value_pairs=[]) + + parts = [] + target_type = 0 + last_was_simple_item = False + while True: + if s.sy in ('*', '**'): + # merged set/dict literal + if target_type == 0: + target_type = 1 if s.sy == '*' else 2 # 'stars' + elif target_type != len(s.sy): + s.error("unexpected %sitem found in %s literal" % ( + s.sy, 'set' if target_type == 1 else 'dict')) + s.next() + if s.sy == '*': + s.error("expected expression, found '*'") + item = p_starred_expr(s) + parts.append(item) + last_was_simple_item = False + else: + item = p_test(s) + if target_type == 0: + target_type = 2 if s.sy == ':' else 1 # dict vs. set + if target_type == 2: + # dict literal + s.expect(':') + key = item + value = p_test(s) + item = ExprNodes.DictItemNode(key.pos, key=key, value=value) + if last_was_simple_item: + parts[-1].append(item) + else: + parts.append([item]) + last_was_simple_item = True + + if s.sy == ',': s.next() - if s.sy == '*': - s.error("expected expression, found '*'") - item = p_starred_expr(s) - parts.append(item) - last_was_simple_item = False - else: - item = p_test(s) - if target_type == 0: - target_type = 2 if s.sy == ':' else 1 # dict vs. set - if target_type == 2: - # dict literal - s.expect(':') - key = item - value = p_test(s) - item = ExprNodes.DictItemNode(key.pos, key=key, value=value) - if last_was_simple_item: - parts[-1].append(item) - else: - parts.append([item]) - last_was_simple_item = True - - if s.sy == ',': - s.next() if s.sy == '}': break - else: - break - + else: + break + if s.sy in ('for', 'async'): - # dict/set comprehension - if len(parts) == 1 and isinstance(parts[0], list) and len(parts[0]) == 1: - item = parts[0][0] - if target_type == 2: - assert isinstance(item, ExprNodes.DictItemNode), type(item) - comprehension_type = Builtin.dict_type - append = ExprNodes.DictComprehensionAppendNode( - item.pos, key_expr=item.key, value_expr=item.value) - else: - comprehension_type = Builtin.set_type - append = ExprNodes.ComprehensionAppendNode(item.pos, expr=item) + # dict/set comprehension + if len(parts) == 1 and isinstance(parts[0], list) and len(parts[0]) == 1: + item = parts[0][0] + if target_type == 2: + assert isinstance(item, ExprNodes.DictItemNode), type(item) + comprehension_type = Builtin.dict_type + append = ExprNodes.DictComprehensionAppendNode( + item.pos, key_expr=item.key, value_expr=item.value) + else: + comprehension_type = Builtin.set_type + append = ExprNodes.ComprehensionAppendNode(item.pos, expr=item) loop = p_comp_for(s, append) s.expect('}') - return ExprNodes.ComprehensionNode(pos, loop=loop, append=append, type=comprehension_type) + return ExprNodes.ComprehensionNode(pos, loop=loop, append=append, type=comprehension_type) else: - # syntax error, try to find a good error message - if len(parts) == 1 and not isinstance(parts[0], list): - s.error("iterable unpacking cannot be used in comprehension") - else: - # e.g. "{1,2,3 for ..." - s.expect('}') - return ExprNodes.DictNode(pos, key_value_pairs=[]) - - s.expect('}') - if target_type == 1: - # (merged) set literal - items = [] - set_items = [] - for part in parts: - if isinstance(part, list): - set_items.extend(part) - else: - if set_items: - items.append(ExprNodes.SetNode(set_items[0].pos, args=set_items)) - set_items = [] - items.append(part) - if set_items: - items.append(ExprNodes.SetNode(set_items[0].pos, args=set_items)) - if len(items) == 1 and items[0].is_set_literal: - return items[0] - return ExprNodes.MergedSequenceNode(pos, args=items, type=Builtin.set_type) - else: - # (merged) dict literal - items = [] - dict_items = [] - for part in parts: - if isinstance(part, list): - dict_items.extend(part) - else: - if dict_items: - items.append(ExprNodes.DictNode(dict_items[0].pos, key_value_pairs=dict_items)) - dict_items = [] - items.append(part) - if dict_items: - items.append(ExprNodes.DictNode(dict_items[0].pos, key_value_pairs=dict_items)) - if len(items) == 1 and items[0].is_dict_literal: - return items[0] - return ExprNodes.MergedDictNode(pos, keyword_args=items, reject_duplicates=False) - - + # syntax error, try to find a good error message + if len(parts) == 1 and not isinstance(parts[0], list): + s.error("iterable unpacking cannot be used in comprehension") + else: + # e.g. "{1,2,3 for ..." + s.expect('}') + return ExprNodes.DictNode(pos, key_value_pairs=[]) + + s.expect('}') + if target_type == 1: + # (merged) set literal + items = [] + set_items = [] + for part in parts: + if isinstance(part, list): + set_items.extend(part) + else: + if set_items: + items.append(ExprNodes.SetNode(set_items[0].pos, args=set_items)) + set_items = [] + items.append(part) + if set_items: + items.append(ExprNodes.SetNode(set_items[0].pos, args=set_items)) + if len(items) == 1 and items[0].is_set_literal: + return items[0] + return ExprNodes.MergedSequenceNode(pos, args=items, type=Builtin.set_type) + else: + # (merged) dict literal + items = [] + dict_items = [] + for part in parts: + if isinstance(part, list): + dict_items.extend(part) + else: + if dict_items: + items.append(ExprNodes.DictNode(dict_items[0].pos, key_value_pairs=dict_items)) + dict_items = [] + items.append(part) + if dict_items: + items.append(ExprNodes.DictNode(dict_items[0].pos, key_value_pairs=dict_items)) + if len(items) == 1 and items[0].is_dict_literal: + return items[0] + return ExprNodes.MergedDictNode(pos, keyword_args=items, reject_duplicates=False) + + # NOTE: no longer in Py3 :) def p_backquote_expr(s): # s.sy == '`' @@ -1423,11 +1423,11 @@ def p_simple_expr_list(s, expr=None): s.next() return exprs - + def p_test_or_starred_expr_list(s, expr=None): exprs = expr is not None and [expr] or [] while s.sy not in expr_terminators: - exprs.append(p_test_or_starred_expr(s)) + exprs.append(p_test_or_starred_expr(s)) if s.sy != ',': break s.next() @@ -1481,7 +1481,7 @@ def p_genexp(s, expr): expr_terminators = cython.declare(set, set([ ')', ']', '}', ':', '=', 'NEWLINE'])) - + #------------------------------------------------------- # # Statements @@ -1495,14 +1495,14 @@ def p_global_statement(s): names = p_ident_list(s) return Nodes.GlobalNode(pos, names = names) - + def p_nonlocal_statement(s): pos = s.position() s.next() names = p_ident_list(s) return Nodes.NonlocalNode(pos, names = names) - + def p_expression_or_assignment(s): expr = p_testlist_star_expr(s) if s.sy == ':' and (expr.is_name or expr.is_subscript or expr.is_attribute): @@ -1523,7 +1523,7 @@ def p_expression_or_assignment(s): expr = p_testlist_star_expr(s) expr_list.append(expr) if len(expr_list) == 1: - if re.match(r"([-+*/%^&|]|<<|>>|\*\*|//|@)=", s.sy): + if re.match(r"([-+*/%^&|]|<<|>>|\*\*|//|@)=", s.sy): lhs = expr_list[0] if isinstance(lhs, ExprNodes.SliceIndexNode): # implementation requires IndexNode @@ -1531,7 +1531,7 @@ def p_expression_or_assignment(s): lhs.pos, base=lhs.base, index=make_slice_node(lhs.pos, lhs.start, lhs.stop)) - elif not isinstance(lhs, (ExprNodes.AttributeNode, ExprNodes.IndexNode, ExprNodes.NameNode)): + elif not isinstance(lhs, (ExprNodes.AttributeNode, ExprNodes.IndexNode, ExprNodes.NameNode)): error(lhs.pos, "Illegal operand for inplace operation.") operator = s.sy[:-1] s.next() @@ -1539,17 +1539,17 @@ def p_expression_or_assignment(s): rhs = p_yield_expression(s) else: rhs = p_testlist(s) - return Nodes.InPlaceAssignmentNode(lhs.pos, operator=operator, lhs=lhs, rhs=rhs) + return Nodes.InPlaceAssignmentNode(lhs.pos, operator=operator, lhs=lhs, rhs=rhs) expr = expr_list[0] return Nodes.ExprStatNode(expr.pos, expr=expr) rhs = expr_list[-1] if len(expr_list) == 2: - return Nodes.SingleAssignmentNode(rhs.pos, lhs=expr_list[0], rhs=rhs) + return Nodes.SingleAssignmentNode(rhs.pos, lhs=expr_list[0], rhs=rhs) else: - return Nodes.CascadedAssignmentNode(rhs.pos, lhs_list=expr_list[:-1], rhs=rhs) + return Nodes.CascadedAssignmentNode(rhs.pos, lhs_list=expr_list[:-1], rhs=rhs) + - def p_print_statement(s): # s.sy == 'print' pos = s.position() @@ -1572,12 +1572,12 @@ def p_print_statement(s): ends_with_comma = 1 break args.append(p_test(s)) - arg_tuple = ExprNodes.TupleNode(pos, args=args) + arg_tuple = ExprNodes.TupleNode(pos, args=args) return Nodes.PrintStatNode(pos, - arg_tuple=arg_tuple, stream=stream, - append_newline=not ends_with_comma) + arg_tuple=arg_tuple, stream=stream, + append_newline=not ends_with_comma) + - def p_exec_statement(s): # s.sy == 'exec' pos = s.position() @@ -1670,43 +1670,43 @@ def p_raise_statement(s): else: return Nodes.ReraiseStatNode(pos) - + def p_import_statement(s): # s.sy in ('import', 'cimport') pos = s.position() kind = s.sy s.next() - items = [p_dotted_name(s, as_allowed=1)] + items = [p_dotted_name(s, as_allowed=1)] while s.sy == ',': s.next() - items.append(p_dotted_name(s, as_allowed=1)) + items.append(p_dotted_name(s, as_allowed=1)) stats = [] - is_absolute = Future.absolute_import in s.context.future_directives + is_absolute = Future.absolute_import in s.context.future_directives for pos, target_name, dotted_name, as_name in items: if kind == 'cimport': - stat = Nodes.CImportStatNode( - pos, - module_name=dotted_name, - as_name=as_name, - is_absolute=is_absolute) + stat = Nodes.CImportStatNode( + pos, + module_name=dotted_name, + as_name=as_name, + is_absolute=is_absolute) else: if as_name and "." in dotted_name: - name_list = ExprNodes.ListNode(pos, args=[ - ExprNodes.IdentifierStringNode(pos, value=s.context.intern_ustring("*"))]) + name_list = ExprNodes.ListNode(pos, args=[ + ExprNodes.IdentifierStringNode(pos, value=s.context.intern_ustring("*"))]) else: name_list = None - stat = Nodes.SingleAssignmentNode( - pos, - lhs=ExprNodes.NameNode(pos, name=as_name or target_name), - rhs=ExprNodes.ImportNode( - pos, - module_name=ExprNodes.IdentifierStringNode(pos, value=dotted_name), - level=0 if is_absolute else None, - name_list=name_list)) + stat = Nodes.SingleAssignmentNode( + pos, + lhs=ExprNodes.NameNode(pos, name=as_name or target_name), + rhs=ExprNodes.ImportNode( + pos, + module_name=ExprNodes.IdentifierStringNode(pos, value=dotted_name), + level=0 if is_absolute else None, + name_list=name_list)) stats.append(stat) - return Nodes.StatListNode(pos, stats=stats) + return Nodes.StatListNode(pos, stats=stats) + - def p_from_import_statement(s, first_statement = 0): # s.sy == 'from' pos = s.position() @@ -1721,7 +1721,7 @@ def p_from_import_statement(s, first_statement = 0): level = None if level is not None and s.sy in ('import', 'cimport'): # we are dealing with "from .. import foo, bar" - dotted_name_pos, dotted_name = s.position(), s.context.intern_ustring('') + dotted_name_pos, dotted_name = s.position(), s.context.intern_ustring('') else: if level is None and Future.absolute_import in s.context.future_directives: level = 0 @@ -1734,7 +1734,7 @@ def p_from_import_statement(s, first_statement = 0): is_cimport = kind == 'cimport' is_parenthesized = False if s.sy == '*': - imported_names = [(s.position(), s.context.intern_ustring("*"), None, None)] + imported_names = [(s.position(), s.context.intern_ustring("*"), None, None)] s.next() else: if s.sy == '(': @@ -1775,11 +1775,11 @@ def p_from_import_statement(s, first_statement = 0): items = [] for (name_pos, name, as_name, kind) in imported_names: imported_name_strings.append( - ExprNodes.IdentifierStringNode(name_pos, value=name)) + ExprNodes.IdentifierStringNode(name_pos, value=name)) items.append( - (name, ExprNodes.NameNode(name_pos, name=as_name or name))) + (name, ExprNodes.NameNode(name_pos, name=as_name or name))) import_list = ExprNodes.ListNode( - imported_names[0][0], args=imported_name_strings) + imported_names[0][0], args=imported_name_strings) return Nodes.FromImportStatNode(pos, module = ExprNodes.ImportNode(dotted_name_pos, module_name = ExprNodes.IdentifierStringNode(pos, value = dotted_name), @@ -1788,8 +1788,8 @@ def p_from_import_statement(s, first_statement = 0): items = items) -imported_name_kinds = cython.declare(set, set(['class', 'struct', 'union'])) - +imported_name_kinds = cython.declare(set, set(['class', 'struct', 'union'])) + def p_imported_name(s, is_cimport): pos = s.position() kind = None @@ -1800,7 +1800,7 @@ def p_imported_name(s, is_cimport): as_name = p_as_name(s) return (pos, name, as_name, kind) - + def p_dotted_name(s, as_allowed): pos = s.position() target_name = p_ident(s) @@ -1811,9 +1811,9 @@ def p_dotted_name(s, as_allowed): names.append(p_ident(s)) if as_allowed: as_name = p_as_name(s) - return (pos, target_name, s.context.intern_ustring(u'.'.join(names)), as_name) + return (pos, target_name, s.context.intern_ustring(u'.'.join(names)), as_name) + - def p_as_name(s): if s.sy == 'IDENT' and s.systring == 'as': s.next() @@ -1821,7 +1821,7 @@ def p_as_name(s): else: return None - + def p_assert_statement(s): # s.sy == 'assert' pos = s.position() @@ -1834,7 +1834,7 @@ def p_assert_statement(s): value = None return Nodes.AssertStatNode(pos, cond = cond, value = value) - + statement_terminators = cython.declare(set, set([';', 'NEWLINE', 'EOF'])) def p_if_statement(s): @@ -1874,25 +1874,25 @@ def p_while_statement(s): condition = test, body = body, else_clause = else_clause) - -def p_for_statement(s, is_async=False): + +def p_for_statement(s, is_async=False): # s.sy == 'for' pos = s.position() s.next() - kw = p_for_bounds(s, allow_testlist=True, is_async=is_async) + kw = p_for_bounds(s, allow_testlist=True, is_async=is_async) body = p_suite(s) else_clause = p_else_clause(s) - kw.update(body=body, else_clause=else_clause, is_async=is_async) + kw.update(body=body, else_clause=else_clause, is_async=is_async) return Nodes.ForStatNode(pos, **kw) - -def p_for_bounds(s, allow_testlist=True, is_async=False): + +def p_for_bounds(s, allow_testlist=True, is_async=False): target = p_for_target(s) if s.sy == 'in': s.next() - iterator = p_for_iterator(s, allow_testlist, is_async=is_async) - return dict(target=target, iterator=iterator) - elif not s.in_python_file and not is_async: + iterator = p_for_iterator(s, allow_testlist, is_async=is_async) + return dict(target=target, iterator=iterator) + elif not s.in_python_file and not is_async: if s.sy == 'from': s.next() bound1 = p_bit_expr(s) @@ -1962,20 +1962,20 @@ def p_target(s, terminator): else: return expr - + def p_for_target(s): return p_target(s, 'in') - -def p_for_iterator(s, allow_testlist=True, is_async=False): + +def p_for_iterator(s, allow_testlist=True, is_async=False): pos = s.position() if allow_testlist: expr = p_testlist(s) else: expr = p_or_test(s) - return (ExprNodes.AsyncIteratorNode if is_async else ExprNodes.IteratorNode)(pos, sequence=expr) + return (ExprNodes.AsyncIteratorNode if is_async else ExprNodes.IteratorNode)(pos, sequence=expr) + - def p_try_statement(s): # s.sy == 'try' pos = s.position() @@ -2043,14 +2043,14 @@ def p_include_statement(s, ctx): include_file_path = s.context.find_include_file(include_file_name, pos) if include_file_path: s.included_files.append(include_file_name) - with Utils.open_source_file(include_file_path) as f: + with Utils.open_source_file(include_file_path) as f: if Options.source_root: import os rel_path = os.path.relpath(include_file_path, Options.source_root) else: rel_path = None source_desc = FileSourceDescriptor(include_file_path, rel_path) - s2 = PyrexScanner(f, source_desc, s, source_encoding=f.encoding, parse_comments=s.parse_comments) + s2 = PyrexScanner(f, source_desc, s, source_encoding=f.encoding, parse_comments=s.parse_comments) tree = p_statement_list(s2, ctx) return tree else: @@ -2058,21 +2058,21 @@ def p_include_statement(s, ctx): else: return Nodes.PassStatNode(pos) - + def p_with_statement(s): - s.next() # 'with' + s.next() # 'with' if s.systring == 'template' and not s.in_python_file: node = p_with_template(s) else: node = p_with_items(s) return node - -def p_with_items(s, is_async=False): + +def p_with_items(s, is_async=False): pos = s.position() if not s.in_python_file and s.sy == 'IDENT' and s.systring in ('nogil', 'gil'): - if is_async: - s.error("with gil/nogil cannot be async") + if is_async: + s.error("with gil/nogil cannot be async") state = s.systring s.next() if s.sy == ',': @@ -2080,7 +2080,7 @@ def p_with_items(s, is_async=False): body = p_with_items(s) else: body = p_suite(s) - return Nodes.GILStatNode(pos, state=state, body=body) + return Nodes.GILStatNode(pos, state=state, body=body) else: manager = p_test(s) target = None @@ -2089,12 +2089,12 @@ def p_with_items(s, is_async=False): target = p_starred_expr(s) if s.sy == ',': s.next() - body = p_with_items(s, is_async=is_async) + body = p_with_items(s, is_async=is_async) else: body = p_suite(s) - return Nodes.WithStatNode(pos, manager=manager, target=target, body=body, is_async=is_async) + return Nodes.WithStatNode(pos, manager=manager, target=target, body=body, is_async=is_async) + - def p_with_template(s): pos = s.position() templates = [] @@ -2255,13 +2255,13 @@ def p_statement(s, ctx, first_statement = 0): s.level = ctx.level decorators = p_decorators(s) if not ctx.allow_struct_enum_decorator and s.sy not in ('def', 'cdef', 'cpdef', 'class', 'async'): - if s.sy == 'IDENT' and s.systring == 'async': - pass # handled below - else: - s.error("Decorators can only be followed by functions or classes") + if s.sy == 'IDENT' and s.systring == 'async': + pass # handled below + else: + s.error("Decorators can only be followed by functions or classes") elif s.sy == 'pass' and cdef_flag: # empty cdef block - return p_pass_statement(s, with_newline=1) + return p_pass_statement(s, with_newline=1) overridable = 0 if s.sy == 'cdef': @@ -2275,11 +2275,11 @@ def p_statement(s, ctx, first_statement = 0): if ctx.level not in ('module', 'module_pxd', 'function', 'c_class', 'c_class_pxd'): s.error('cdef statement not allowed here') s.level = ctx.level - node = p_cdef_statement(s, ctx(overridable=overridable)) + node = p_cdef_statement(s, ctx(overridable=overridable)) if decorators is not None: - tup = (Nodes.CFuncDefNode, Nodes.CVarDefNode, Nodes.CClassDefNode) + tup = (Nodes.CFuncDefNode, Nodes.CVarDefNode, Nodes.CClassDefNode) if ctx.allow_struct_enum_decorator: - tup += (Nodes.CStructOrUnionDefNode, Nodes.CEnumDefNode) + tup += (Nodes.CStructOrUnionDefNode, Nodes.CEnumDefNode) if not isinstance(node, tup): s.error("Decorators can only be followed by functions or classes") node.decorators = decorators @@ -2322,22 +2322,22 @@ def p_statement(s, ctx, first_statement = 0): return p_try_statement(s) elif s.sy == 'with': return p_with_statement(s) - elif s.sy == 'async': - s.next() - return p_async_statement(s, ctx, decorators) + elif s.sy == 'async': + s.next() + return p_async_statement(s, ctx, decorators) else: - if s.sy == 'IDENT' and s.systring == 'async': - ident_name = s.systring - # PEP 492 enables the async/await keywords when it spots "async def ..." - s.next() - if s.sy == 'def': - return p_async_statement(s, ctx, decorators) - elif decorators: - s.error("Decorators can only be followed by functions or classes") - s.put_back('IDENT', ident_name) # re-insert original token - return p_simple_statement_list(s, ctx, first_statement=first_statement) - - + if s.sy == 'IDENT' and s.systring == 'async': + ident_name = s.systring + # PEP 492 enables the async/await keywords when it spots "async def ..." + s.next() + if s.sy == 'def': + return p_async_statement(s, ctx, decorators) + elif decorators: + s.error("Decorators can only be followed by functions or classes") + s.put_back('IDENT', ident_name) # re-insert original token + return p_simple_statement_list(s, ctx, first_statement=first_statement) + + def p_statement_list(s, ctx, first_statement = 0): # Parse a series of statements separated by newlines. pos = s.position() @@ -2412,7 +2412,7 @@ def p_positional_and_keyword_args(s, end_sy_set, templates = None): arg = Nodes.CComplexBaseTypeNode(base_type.pos, base_type = base_type, declarator = declarator) parsed_type = True - keyword_node = ExprNodes.IdentifierStringNode(arg.pos, value=ident) + keyword_node = ExprNodes.IdentifierStringNode(arg.pos, value=ident) keyword_args.append((keyword_node, arg)) was_keyword = True @@ -2455,31 +2455,31 @@ def p_calling_convention(s): else: return "" - + calling_convention_words = cython.declare( set, set(["__stdcall", "__cdecl", "__fastcall"])) - + def p_c_complex_base_type(s, templates = None): # s.sy == '(' pos = s.position() s.next() - base_type = p_c_base_type(s, templates=templates) - declarator = p_c_declarator(s, empty=True) - type_node = Nodes.CComplexBaseTypeNode( - pos, base_type=base_type, declarator=declarator) - if s.sy == ',': - components = [type_node] - while s.sy == ',': - s.next() - if s.sy == ')': - break - base_type = p_c_base_type(s, templates=templates) - declarator = p_c_declarator(s, empty=True) - components.append(Nodes.CComplexBaseTypeNode( - pos, base_type=base_type, declarator=declarator)) - type_node = Nodes.CTupleBaseTypeNode(pos, components = components) - + base_type = p_c_base_type(s, templates=templates) + declarator = p_c_declarator(s, empty=True) + type_node = Nodes.CComplexBaseTypeNode( + pos, base_type=base_type, declarator=declarator) + if s.sy == ',': + components = [type_node] + while s.sy == ',': + s.next() + if s.sy == ')': + break + base_type = p_c_base_type(s, templates=templates) + declarator = p_c_declarator(s, empty=True) + components.append(Nodes.CComplexBaseTypeNode( + pos, base_type=base_type, declarator=declarator)) + type_node = Nodes.CTupleBaseTypeNode(pos, components = components) + s.expect(')') if s.sy == '[': if is_memoryviewslice_access(s): @@ -2728,7 +2728,7 @@ special_basic_c_types = cython.declare(dict, { # name : (signed, longness) "Py_UNICODE" : (0, 0), "Py_UCS4" : (0, 0), - "Py_hash_t" : (2, 0), + "Py_hash_t" : (2, 0), "Py_ssize_t" : (2, 0), "ssize_t" : (2, 0), "size_t" : (0, 0), @@ -2783,7 +2783,7 @@ def p_c_declarator(s, ctx = Ctx(), empty = 0, is_type = 0, cmethod_flag = 0, if s.sy == '(': s.next() if s.sy == ')' or looking_at_name(s): - base = Nodes.CNameDeclaratorNode(pos, name=s.context.intern_ustring(u""), cname=None) + base = Nodes.CNameDeclaratorNode(pos, name=s.context.intern_ustring(u""), cname=None) result = p_c_func_declarator(s, pos, ctx, base, cmethod_flag) else: result = p_c_declarator(s, ctx, empty = empty, is_type = is_type, @@ -2835,8 +2835,8 @@ supported_overloaded_operators = cython.declare(set, set([ '+', '-', '*', '/', '%', '++', '--', '~', '|', '&', '^', '<<', '>>', ',', '==', '!=', '>=', '>', '<=', '<', - '[]', '()', '!', '=', - 'bool', + '[]', '()', '!', '=', + 'bool', ])) def p_c_simple_declarator(s, ctx, empty, is_type, cmethod_flag, @@ -2877,7 +2877,7 @@ def p_c_simple_declarator(s, ctx, empty, is_type, cmethod_flag, else: rhs = None if s.sy == 'IDENT': - name = s.systring + name = s.systring if empty: error(s.position(), "Declarator should be empty") s.next() @@ -2913,13 +2913,13 @@ def p_c_simple_declarator(s, ctx, empty, is_type, cmethod_flag, s.error("Overloading operator '%s' not yet supported." % op, fatal=False) name += op - elif op == 'IDENT': - op = s.systring; - if op not in supported_overloaded_operators: - s.error("Overloading operator '%s' not yet supported." % op, - fatal=False) - name = name + ' ' + op - s.next() + elif op == 'IDENT': + op = s.systring; + if op not in supported_overloaded_operators: + s.error("Overloading operator '%s' not yet supported." % op, + fatal=False) + name = name + ' ' + op + s.next() result = Nodes.CNameDeclaratorNode(pos, name = name, cname = cname, default = rhs) result.calling_convention = calling_convention @@ -2955,9 +2955,9 @@ def p_exception_value_clause(s): name = s.systring s.next() exc_val = p_name(s, name) - elif s.sy == '*': - exc_val = ExprNodes.CharNode(s.position(), value=u'*') - s.next() + elif s.sy == '*': + exc_val = ExprNodes.CharNode(s.position(), value=u'*') + s.next() else: if s.sy == '?': exc_check = 1 @@ -2965,7 +2965,7 @@ def p_exception_value_clause(s): exc_val = p_test(s) return exc_val, exc_check -c_arg_list_terminators = cython.declare(set, set(['*', '**', '.', ')', ':'])) +c_arg_list_terminators = cython.declare(set, set(['*', '**', '.', ')', ':'])) def p_c_arg_list(s, ctx = Ctx(), in_pyfunc = 0, cmethod_flag = 0, nonempty_declarators = 0, kw_only = 0, annotated = 1): @@ -3278,14 +3278,14 @@ def p_c_func_or_var_declaration(s, pos, ctx): is_const_method = 1 else: is_const_method = 0 - if s.sy == '->': - # Special enough to give a better error message and keep going. - s.error( - "Return type annotation is not allowed in cdef/cpdef signatures. " - "Please define it before the function name, as in C signatures.", - fatal=False) - s.next() - p_test(s) # Keep going, but ignore result. + if s.sy == '->': + # Special enough to give a better error message and keep going. + s.error( + "Return type annotation is not allowed in cdef/cpdef signatures. " + "Please define it before the function name, as in C signatures.", + fatal=False) + s.next() + p_test(s) # Keep going, but ignore result. if s.sy == ':': if ctx.level not in ('module', 'c_class', 'module_pxd', 'c_class_pxd', 'cpp_class') and not ctx.templates: s.error("C function definition not allowed here") @@ -3362,59 +3362,59 @@ def p_decorators(s): s.next() decstring = p_dotted_name(s, as_allowed=0)[2] names = decstring.split('.') - decorator = ExprNodes.NameNode(pos, name=s.context.intern_ustring(names[0])) + decorator = ExprNodes.NameNode(pos, name=s.context.intern_ustring(names[0])) for name in names[1:]: - decorator = ExprNodes.AttributeNode( - pos, attribute=s.context.intern_ustring(name), obj=decorator) + decorator = ExprNodes.AttributeNode( + pos, attribute=s.context.intern_ustring(name), obj=decorator) if s.sy == '(': decorator = p_call(s, decorator) decorators.append(Nodes.DecoratorNode(pos, decorator=decorator)) s.expect_newline("Expected a newline after decorator") return decorators - -def _reject_cdef_modifier_in_py(s, name): - """Step over incorrectly placed cdef modifiers (@see _CDEF_MODIFIERS) to provide a good error message for them. - """ - if s.sy == 'IDENT' and name in _CDEF_MODIFIERS: - # Special enough to provide a good error message. - s.error("Cannot use cdef modifier '%s' in Python function signature. Use a decorator instead." % name, fatal=False) - return p_ident(s) # Keep going, in case there are other errors. - return name - - -def p_def_statement(s, decorators=None, is_async_def=False): + +def _reject_cdef_modifier_in_py(s, name): + """Step over incorrectly placed cdef modifiers (@see _CDEF_MODIFIERS) to provide a good error message for them. + """ + if s.sy == 'IDENT' and name in _CDEF_MODIFIERS: + # Special enough to provide a good error message. + s.error("Cannot use cdef modifier '%s' in Python function signature. Use a decorator instead." % name, fatal=False) + return p_ident(s) # Keep going, in case there are other errors. + return name + + +def p_def_statement(s, decorators=None, is_async_def=False): # s.sy == 'def' pos = s.position() - # PEP 492 switches the async/await keywords on in "async def" functions - if is_async_def: - s.enter_async() + # PEP 492 switches the async/await keywords on in "async def" functions + if is_async_def: + s.enter_async() s.next() - name = _reject_cdef_modifier_in_py(s, p_ident(s)) - s.expect( - '(', - "Expected '(', found '%s'. Did you use cdef syntax in a Python declaration? " - "Use decorators and Python type annotations instead." % ( - s.systring if s.sy == 'IDENT' else s.sy)) + name = _reject_cdef_modifier_in_py(s, p_ident(s)) + s.expect( + '(', + "Expected '(', found '%s'. Did you use cdef syntax in a Python declaration? " + "Use decorators and Python type annotations instead." % ( + s.systring if s.sy == 'IDENT' else s.sy)) args, star_arg, starstar_arg = p_varargslist(s, terminator=')') s.expect(')') - _reject_cdef_modifier_in_py(s, s.systring) + _reject_cdef_modifier_in_py(s, s.systring) return_type_annotation = None if s.sy == '->': s.next() return_type_annotation = p_test(s) - _reject_cdef_modifier_in_py(s, s.systring) - + _reject_cdef_modifier_in_py(s, s.systring) + doc, body = p_suite_with_docstring(s, Ctx(level='function')) - if is_async_def: - s.exit_async() - - return Nodes.DefNode( - pos, name=name, args=args, star_arg=star_arg, starstar_arg=starstar_arg, - doc=doc, body=body, decorators=decorators, is_async_def=is_async_def, - return_type_annotation=return_type_annotation) - - + if is_async_def: + s.exit_async() + + return Nodes.DefNode( + pos, name=name, args=args, star_arg=star_arg, starstar_arg=starstar_arg, + doc=doc, body=body, decorators=decorators, is_async_def=is_async_def, + return_type_annotation=return_type_annotation) + + def p_varargslist(s, terminator=')', annotated=1): args = p_c_arg_list(s, in_pyfunc = 1, nonempty_declarators = 1, annotated = annotated) @@ -3433,8 +3433,8 @@ def p_varargslist(s, terminator=')', annotated=1): if s.sy == '**': s.next() starstar_arg = p_py_arg_decl(s, annotated=annotated) - if s.sy == ',': - s.next() + if s.sy == ',': + s.next() return (args, star_arg, starstar_arg) def p_py_arg_decl(s, annotated = 1): @@ -3446,18 +3446,18 @@ def p_py_arg_decl(s, annotated = 1): annotation = p_test(s) return Nodes.PyArgDeclNode(pos, name = name, annotation = annotation) - + def p_class_statement(s, decorators): # s.sy == 'class' pos = s.position() s.next() - class_name = EncodedString(p_ident(s)) - class_name.encoding = s.source_encoding # FIXME: why is this needed? + class_name = EncodedString(p_ident(s)) + class_name.encoding = s.source_encoding # FIXME: why is this needed? arg_tuple = None keyword_dict = None if s.sy == '(': - positional_args, keyword_args = p_call_parse_args(s, allow_genexp=False) - arg_tuple, keyword_dict = p_call_build_packed_args(pos, positional_args, keyword_args) + positional_args, keyword_args = p_call_parse_args(s, allow_genexp=False) + arg_tuple, keyword_dict = p_call_build_packed_args(pos, positional_args, keyword_args) if arg_tuple is None: # XXX: empty arg_tuple arg_tuple = ExprNodes.TupleNode(pos, args=[]) @@ -3469,7 +3469,7 @@ def p_class_statement(s, decorators): doc=doc, body=body, decorators=decorators, force_py3_semantics=s.context.language_level >= 3) - + def p_c_class_definition(s, pos, ctx): # s.sy == 'class' s.next() @@ -3489,7 +3489,7 @@ def p_c_class_definition(s, pos, ctx): objstruct_name = None typeobj_name = None bases = None - check_size = None + check_size = None if s.sy == '(': positional_args, keyword_args = p_call_parse_args(s, allow_genexp=False) if keyword_args: @@ -3501,7 +3501,7 @@ def p_c_class_definition(s, pos, ctx): if s.sy == '[': if ctx.visibility not in ('public', 'extern') and not ctx.api: error(s.position(), "Name options only allowed for 'public', 'api', or 'extern' C class") - objstruct_name, typeobj_name, check_size = p_c_class_options(s) + objstruct_name, typeobj_name, check_size = p_c_class_options(s) if s.sy == ':': if ctx.level == 'module_pxd': body_level = 'c_class_pxd' @@ -3540,16 +3540,16 @@ def p_c_class_definition(s, pos, ctx): bases = bases, objstruct_name = objstruct_name, typeobj_name = typeobj_name, - check_size = check_size, + check_size = check_size, in_pxd = ctx.level == 'module_pxd', doc = doc, body = body) - + def p_c_class_options(s): objstruct_name = None typeobj_name = None - check_size = None + check_size = None s.expect('[') while 1: if s.sy != 'IDENT': @@ -3560,16 +3560,16 @@ def p_c_class_options(s): elif s.systring == 'type': s.next() typeobj_name = p_ident(s) - elif s.systring == 'check_size': - s.next() - check_size = p_ident(s) - if check_size not in ('ignore', 'warn', 'error'): - s.error("Expected one of ignore, warn or error, found %r" % check_size) + elif s.systring == 'check_size': + s.next() + check_size = p_ident(s) + if check_size not in ('ignore', 'warn', 'error'): + s.error("Expected one of ignore, warn or error, found %r" % check_size) if s.sy != ',': break s.next() - s.expect(']', "Expected 'object', 'type' or 'check_size'") - return objstruct_name, typeobj_name, check_size + s.expect(']', "Expected 'object', 'type' or 'check_size'") + return objstruct_name, typeobj_name, check_size def p_property_decl(s): @@ -3648,64 +3648,64 @@ def p_code(s, level=None, ctx=Ctx): repr(s.sy), repr(s.systring))) return body - + _match_compiler_directive_comment = cython.declare(object, re.compile( r"^#\s*cython\s*:\s*((\w|[.])+\s*=.*)$").match) - + def p_compiler_directive_comments(s): result = {} while s.sy == 'commentline': - pos = s.position() + pos = s.position() m = _match_compiler_directive_comment(s.systring) if m: - directives_string = m.group(1).strip() + directives_string = m.group(1).strip() try: - new_directives = Options.parse_directive_list(directives_string, ignore_unknown=True) - except ValueError as e: + new_directives = Options.parse_directive_list(directives_string, ignore_unknown=True) + except ValueError as e: s.error(e.args[0], fatal=False) - s.next() - continue - - for name in new_directives: - if name not in result: - pass - elif new_directives[name] == result[name]: - warning(pos, "Duplicate directive found: %s" % (name,)) - else: - s.error("Conflicting settings found for top-level directive %s: %r and %r" % ( - name, result[name], new_directives[name]), pos=pos) - - if 'language_level' in new_directives: - # Make sure we apply the language level already to the first token that follows the comments. - s.context.set_language_level(new_directives['language_level']) - - result.update(new_directives) - + s.next() + continue + + for name in new_directives: + if name not in result: + pass + elif new_directives[name] == result[name]: + warning(pos, "Duplicate directive found: %s" % (name,)) + else: + s.error("Conflicting settings found for top-level directive %s: %r and %r" % ( + name, result[name], new_directives[name]), pos=pos) + + if 'language_level' in new_directives: + # Make sure we apply the language level already to the first token that follows the comments. + s.context.set_language_level(new_directives['language_level']) + + result.update(new_directives) + s.next() return result - + def p_module(s, pxd, full_module_name, ctx=Ctx): pos = s.position() directive_comments = p_compiler_directive_comments(s) s.parse_comments = False - if s.context.language_level is None: - s.context.set_language_level(2) # Arcadia default. - - if s.context.language_level is None: - s.context.set_language_level(2) - if pos[0].filename: - import warnings - warnings.warn( - "Cython directive 'language_level' not set, using 2 for now (Py2). " - "This will change in a later release! File: %s" % pos[0].filename, - FutureWarning, - stacklevel=1 if cython.compiled else 2, - ) - + if s.context.language_level is None: + s.context.set_language_level(2) # Arcadia default. + + if s.context.language_level is None: + s.context.set_language_level(2) + if pos[0].filename: + import warnings + warnings.warn( + "Cython directive 'language_level' not set, using 2 for now (Py2). " + "This will change in a later release! File: %s" % pos[0].filename, + FutureWarning, + stacklevel=1 if cython.compiled else 2, + ) + doc = p_doc_string(s) if pxd: level = 'module_pxd' @@ -3720,16 +3720,16 @@ def p_module(s, pxd, full_module_name, ctx=Ctx): full_module_name = full_module_name, directive_comments = directive_comments) -def p_template_definition(s): - name = p_ident(s) - if s.sy == '=': - s.expect('=') - s.expect('*') - required = False - else: - required = True - return name, required - +def p_template_definition(s): + name = p_ident(s) + if s.sy == '=': + s.expect('=') + s.expect('*') + required = False + else: + required = True + return name, required + def p_cpp_class_definition(s, pos, ctx): # s.sy == 'cppclass' s.next() @@ -3742,21 +3742,21 @@ def p_cpp_class_definition(s, pos, ctx): error(pos, "Qualified class name not allowed C++ class") if s.sy == '[': s.next() - templates = [p_template_definition(s)] + templates = [p_template_definition(s)] while s.sy == ',': s.next() - templates.append(p_template_definition(s)) + templates.append(p_template_definition(s)) s.expect(']') - template_names = [name for name, required in templates] + template_names = [name for name, required in templates] else: templates = None - template_names = None + template_names = None if s.sy == '(': s.next() - base_classes = [p_c_base_type(s, templates = template_names)] + base_classes = [p_c_base_type(s, templates = template_names)] while s.sy == ',': s.next() - base_classes.append(p_c_base_type(s, templates = template_names)) + base_classes.append(p_c_base_type(s, templates = template_names)) s.expect(')') else: base_classes = [] @@ -3769,7 +3769,7 @@ def p_cpp_class_definition(s, pos, ctx): s.expect_indent() attributes = [] body_ctx = Ctx(visibility = ctx.visibility, level='cpp_class', nogil=nogil or ctx.nogil) - body_ctx.templates = template_names + body_ctx.templates = template_names while s.sy != 'DEDENT': if s.sy != 'pass': attributes.append(p_cpp_class_attribute(s, body_ctx)) @@ -3795,13 +3795,13 @@ def p_cpp_class_attribute(s, ctx): decorators = p_decorators(s) if s.systring == 'cppclass': return p_cpp_class_definition(s, s.position(), ctx) - elif s.systring == 'ctypedef': - return p_ctypedef_statement(s, ctx) - elif s.sy == 'IDENT' and s.systring in struct_enum_union: - if s.systring != 'enum': - return p_cpp_class_definition(s, s.position(), ctx) - else: - return p_struct_enum(s, s.position(), ctx) + elif s.systring == 'ctypedef': + return p_ctypedef_statement(s, ctx) + elif s.sy == 'IDENT' and s.systring in struct_enum_union: + if s.systring != 'enum': + return p_cpp_class_definition(s, s.position(), ctx) + else: + return p_struct_enum(s, s.position(), ctx) else: node = p_c_func_or_var_declaration(s, s.position(), ctx) if decorators is not None: @@ -3829,7 +3829,7 @@ def print_parse_tree(f, node, level, key = None): t = type(node) if t is tuple: f.write("(%s @ %s\n" % (node[0], node[1])) - for i in range(2, len(node)): + for i in range(2, len(node)): print_parse_tree(f, node[i], level+1) f.write("%s)\n" % ind) return @@ -3845,7 +3845,7 @@ def print_parse_tree(f, node, level, key = None): return elif t is list: f.write("[\n") - for i in range(len(node)): + for i in range(len(node)): print_parse_tree(f, node[i], level+1) f.write("%s]\n" % ind) return diff --git a/contrib/tools/cython/Cython/Compiler/Pipeline.py b/contrib/tools/cython/Cython/Compiler/Pipeline.py index 891937248b..5194c3e49b 100644 --- a/contrib/tools/cython/Cython/Compiler/Pipeline.py +++ b/contrib/tools/cython/Cython/Compiler/Pipeline.py @@ -14,7 +14,7 @@ from . import Naming # def dumptree(t): # For quick debugging in pipelines - print(t.dump()) + print(t.dump()) return t def abort_on_errors(node): @@ -29,7 +29,7 @@ def parse_stage_factory(context): full_module_name = compsrc.full_module_name initial_pos = (source_desc, 1, 0) saved_cimport_from_pyx, Options.cimport_from_pyx = Options.cimport_from_pyx, False - scope = context.find_module(full_module_name, pos = initial_pos, need_pxd = 0) + scope = context.find_module(full_module_name, pos = initial_pos, need_pxd = 0) Options.cimport_from_pyx = saved_cimport_from_pyx tree = context.parse(source_desc, scope, pxd = 0, full_module_name = full_module_name) tree.compilation_source = compsrc @@ -54,20 +54,20 @@ def generate_pyx_code_stage_factory(options, result): return result return generate_pyx_code_stage - + def inject_pxd_code_stage_factory(context): def inject_pxd_code_stage(module_node): - for name, (statlistnode, scope) in context.pxds.items(): + for name, (statlistnode, scope) in context.pxds.items(): module_node.merge_in(statlistnode, scope) return module_node return inject_pxd_code_stage - + def use_utility_code_definitions(scope, target, seen=None): if seen is None: seen = set() - for entry in scope.entries.values(): + for entry in scope.entries.values(): if entry in seen: continue @@ -79,54 +79,54 @@ def use_utility_code_definitions(scope, target, seen=None): elif entry.as_module: use_utility_code_definitions(entry.as_module, target, seen) - -def sort_utility_codes(utilcodes): - ranks = {} - def get_rank(utilcode): - if utilcode not in ranks: - ranks[utilcode] = 0 # prevent infinite recursion on circular dependencies - original_order = len(ranks) - ranks[utilcode] = 1 + min([get_rank(dep) for dep in utilcode.requires or ()] or [-1]) + original_order * 1e-8 - return ranks[utilcode] - for utilcode in utilcodes: - get_rank(utilcode) - return [utilcode for utilcode, _ in sorted(ranks.items(), key=lambda kv: kv[1])] - - -def normalize_deps(utilcodes): - deps = {} - for utilcode in utilcodes: - deps[utilcode] = utilcode - - def unify_dep(dep): - if dep in deps: - return deps[dep] - else: - deps[dep] = dep - return dep - - for utilcode in utilcodes: - utilcode.requires = [unify_dep(dep) for dep in utilcode.requires or ()] - - + +def sort_utility_codes(utilcodes): + ranks = {} + def get_rank(utilcode): + if utilcode not in ranks: + ranks[utilcode] = 0 # prevent infinite recursion on circular dependencies + original_order = len(ranks) + ranks[utilcode] = 1 + min([get_rank(dep) for dep in utilcode.requires or ()] or [-1]) + original_order * 1e-8 + return ranks[utilcode] + for utilcode in utilcodes: + get_rank(utilcode) + return [utilcode for utilcode, _ in sorted(ranks.items(), key=lambda kv: kv[1])] + + +def normalize_deps(utilcodes): + deps = {} + for utilcode in utilcodes: + deps[utilcode] = utilcode + + def unify_dep(dep): + if dep in deps: + return deps[dep] + else: + deps[dep] = dep + return dep + + for utilcode in utilcodes: + utilcode.requires = [unify_dep(dep) for dep in utilcode.requires or ()] + + def inject_utility_code_stage_factory(context): def inject_utility_code_stage(module_node): - module_node.prepare_utility_code() + module_node.prepare_utility_code() use_utility_code_definitions(context.cython_scope, module_node.scope) - module_node.scope.utility_code_list = sort_utility_codes(module_node.scope.utility_code_list) - normalize_deps(module_node.scope.utility_code_list) + module_node.scope.utility_code_list = sort_utility_codes(module_node.scope.utility_code_list) + normalize_deps(module_node.scope.utility_code_list) added = [] # Note: the list might be extended inside the loop (if some utility code # pulls in other utility code, explicitly or implicitly) for utilcode in module_node.scope.utility_code_list: - if utilcode in added: - continue + if utilcode in added: + continue added.append(utilcode) if utilcode.requires: for dep in utilcode.requires: - if dep not in added and dep not in module_node.scope.utility_code_list: + if dep not in added and dep not in module_node.scope.utility_code_list: module_node.scope.utility_code_list.append(dep) - tree = utilcode.get_tree(cython_scope=context.cython_scope) + tree = utilcode.get_tree(cython_scope=context.cython_scope) if tree: module_node.merge_in(tree.body, tree.scope, merge_scope=True) return module_node @@ -141,7 +141,7 @@ def create_pipeline(context, mode, exclude_classes=()): assert mode in ('pyx', 'py', 'pxd') from .Visitor import PrintTree from .ParseTreeTransforms import WithTransform, NormalizeTree, PostParse, PxdPostParse - from .ParseTreeTransforms import ForwardDeclareTypes, InjectGilHandling, AnalyseDeclarationsTransform + from .ParseTreeTransforms import ForwardDeclareTypes, InjectGilHandling, AnalyseDeclarationsTransform from .ParseTreeTransforms import AnalyseExpressionsTransform, FindInvalidUseOfFusedTypes from .ParseTreeTransforms import CreateClosureClasses, MarkClosureVisitor, DecoratorTransform from .ParseTreeTransforms import TrackNumpyAttributes, InterpretCompilerDirectives, TransformBuiltinMethods @@ -186,7 +186,7 @@ def create_pipeline(context, mode, exclude_classes=()): InterpretCompilerDirectives(context, context.compiler_directives), ParallelRangeTransform(context), AdjustDefByDirectives(context), - WithTransform(context), + WithTransform(context), MarkClosureVisitor(context), _align_function_definitions, RemoveUnreachableCode(context), @@ -194,12 +194,12 @@ def create_pipeline(context, mode, exclude_classes=()): FlattenInListTransform(), DecoratorTransform(context), ForwardDeclareTypes(context), - InjectGilHandling(), + InjectGilHandling(), AnalyseDeclarationsTransform(context), AutoTestDictTransform(context), EmbedSignature(context), EarlyReplaceBuiltinCalls(context), ## Necessary? - TransformBuiltinMethods(context), + TransformBuiltinMethods(context), MarkParallelAssignments(context), ControlFlowAnalysis(context), RemoveUnreachableCode(context), @@ -211,8 +211,8 @@ def create_pipeline(context, mode, exclude_classes=()): AnalyseExpressionsTransform(context), FindInvalidUseOfFusedTypes(context), ExpandInplaceOperators(context), - IterationTransform(context), - SwitchTransform(context), + IterationTransform(context), + SwitchTransform(context), OptimizeBuiltinCalls(context), ## Necessary? CreateClosureClasses(context), ## After all lookups and type inference CalculateQualifiedNamesTransform(context), @@ -344,7 +344,7 @@ def run_pipeline(pipeline, source, printtree=True): continue if DebugFlags.debug_verbose_pipeline: t = time() - print("Entering pipeline phase %r" % phase) + print("Entering pipeline phase %r" % phase) # create a new wrapper for each step to show the name in profiles phase_name = getattr(phase, '__name__', type(phase).__name__) try: @@ -354,16 +354,16 @@ def run_pipeline(pipeline, source, printtree=True): run = _pipeline_entry_points[phase_name] = exec_ns[phase_name] data = run(phase, data) if DebugFlags.debug_verbose_pipeline: - print(" %.3f seconds" % (time() - t)) - except CompileError as err: + print(" %.3f seconds" % (time() - t)) + except CompileError as err: # err is set Errors.report_error(err, use_stack=False) error = err - except InternalError as err: + except InternalError as err: # Only raise if there was not an earlier error if Errors.num_errors == 0: raise error = err - except AbortError as err: + except AbortError as err: error = err return (error, data) diff --git a/contrib/tools/cython/Cython/Compiler/PyrexTypes.py b/contrib/tools/cython/Cython/Compiler/PyrexTypes.py index 913d163597..3d4931cea6 100644 --- a/contrib/tools/cython/Cython/Compiler/PyrexTypes.py +++ b/contrib/tools/cython/Cython/Compiler/PyrexTypes.py @@ -6,19 +6,19 @@ from __future__ import absolute_import import copy import hashlib -import re - -try: - reduce -except NameError: - from functools import reduce - -from Cython.Utils import cached_function +import re + +try: + reduce +except NameError: + from functools import reduce + +from Cython.Utils import cached_function from .Code import UtilityCode, LazyUtilityCode, TempitaUtilityCode from . import StringEncoding from . import Naming -from .Errors import error, warning +from .Errors import error, warning class BaseType(object): @@ -27,9 +27,9 @@ class BaseType(object): # List of attribute names of any subtypes subtypes = [] - _empty_declaration = None + _empty_declaration = None _specialization_name = None - default_format_spec = None + default_format_spec = None def can_coerce_to_pyobject(self, env): return False @@ -37,20 +37,20 @@ class BaseType(object): def can_coerce_from_pyobject(self, env): return False - def can_coerce_to_pystring(self, env, format_spec=None): - return False - - def convert_to_pystring(self, cvalue, code, format_spec=None): - raise NotImplementedError("C types that support string formatting must override this method") - + def can_coerce_to_pystring(self, env, format_spec=None): + return False + + def convert_to_pystring(self, cvalue, code, format_spec=None): + raise NotImplementedError("C types that support string formatting must override this method") + def cast_code(self, expr_code): - return "((%s)%s)" % (self.empty_declaration_code(), expr_code) + return "((%s)%s)" % (self.empty_declaration_code(), expr_code) + + def empty_declaration_code(self): + if self._empty_declaration is None: + self._empty_declaration = self.declaration_code('') + return self._empty_declaration - def empty_declaration_code(self): - if self._empty_declaration is None: - self._empty_declaration = self.declaration_code('') - return self._empty_declaration - def specialization_name(self): if self._specialization_name is None: # This is not entirely robust. @@ -117,7 +117,7 @@ class BaseType(object): http://en.cppreference.com/w/cpp/language/function_template#Template_argument_deduction """ - return {} + return {} def __lt__(self, other): """ @@ -249,7 +249,7 @@ class PyrexType(BaseType): is_returncode = 0 is_error = 0 is_buffer = 0 - is_ctuple = 0 + is_ctuple = 0 is_memoryviewslice = 0 is_pythran_expr = 0 is_numpy_buffer = 0 @@ -338,7 +338,7 @@ def public_decl(base_code, dll_linkage): else: return base_code -def create_typedef_type(name, base_type, cname, is_external=0, namespace=None): +def create_typedef_type(name, base_type, cname, is_external=0, namespace=None): is_fused = base_type.is_fused if base_type.is_complex or is_fused: if is_external: @@ -351,7 +351,7 @@ def create_typedef_type(name, base_type, cname, is_external=0, namespace=None): return base_type else: - return CTypedefType(name, base_type, cname, is_external, namespace) + return CTypedefType(name, base_type, cname, is_external, namespace) class CTypedefType(BaseType): @@ -375,13 +375,13 @@ class CTypedefType(BaseType): subtypes = ['typedef_base_type'] - def __init__(self, name, base_type, cname, is_external=0, namespace=None): + def __init__(self, name, base_type, cname, is_external=0, namespace=None): assert not base_type.is_complex self.typedef_name = name self.typedef_cname = cname self.typedef_base_type = base_type self.typedef_is_external = is_external - self.typedef_namespace = namespace + self.typedef_namespace = namespace def invalid_value(self): return self.typedef_base_type.invalid_value() @@ -395,8 +395,8 @@ class CTypedefType(BaseType): base_code = self.typedef_name else: base_code = public_decl(self.typedef_cname, dll_linkage) - if self.typedef_namespace is not None and not pyrex: - base_code = "%s::%s" % (self.typedef_namespace.empty_declaration_code(), base_code) + if self.typedef_namespace is not None and not pyrex: + base_code = "%s::%s" % (self.typedef_namespace.empty_declaration_code(), base_code) return self.base_declaration_code(base_code, entity_code) def as_argument_type(self): @@ -411,15 +411,15 @@ class CTypedefType(BaseType): else: return BaseType.cast_code(self, expr_code) - def specialize(self, values): - base_type = self.typedef_base_type.specialize(values) - namespace = self.typedef_namespace.specialize(values) if self.typedef_namespace else None - if base_type is self.typedef_base_type and namespace is self.typedef_namespace: - return self - else: - return create_typedef_type(self.typedef_name, base_type, self.typedef_cname, - 0, namespace) - + def specialize(self, values): + base_type = self.typedef_base_type.specialize(values) + namespace = self.typedef_namespace.specialize(values) if self.typedef_namespace else None + if base_type is self.typedef_base_type and namespace is self.typedef_namespace: + return self + else: + return create_typedef_type(self.typedef_name, base_type, self.typedef_cname, + 0, namespace) + def __repr__(self): return "<CTypedefType %s>" % self.typedef_cname @@ -428,7 +428,7 @@ class CTypedefType(BaseType): def _create_utility_code(self, template_utility_code, template_function_name): - type_name = type_identifier(self.typedef_cname) + type_name = type_identifier(self.typedef_cname) utility_code = template_utility_code.specialize( type = self.typedef_cname, TypeName = type_name) @@ -441,9 +441,9 @@ class CTypedefType(BaseType): base_type = self.typedef_base_type if type(base_type) is CIntType: self.to_py_function = "__Pyx_PyInt_From_" + self.specialization_name() - env.use_utility_code(TempitaUtilityCode.load_cached( + env.use_utility_code(TempitaUtilityCode.load_cached( "CIntToPy", "TypeConversion.c", - context={"TYPE": self.empty_declaration_code(), + context={"TYPE": self.empty_declaration_code(), "TO_PY_FUNCTION": self.to_py_function})) return True elif base_type.is_float: @@ -451,17 +451,17 @@ class CTypedefType(BaseType): elif base_type.is_complex: pass # XXX implement! pass - elif base_type.is_cpp_string: - cname = "__pyx_convert_PyObject_string_to_py_%s" % type_identifier(self) - context = { - 'cname': cname, - 'type': self.typedef_cname, - } - from .UtilityCode import CythonUtilityCode - env.use_utility_code(CythonUtilityCode.load( - "string.to_py", "CppConvert.pyx", context=context)) - self.to_py_function = cname - return True + elif base_type.is_cpp_string: + cname = "__pyx_convert_PyObject_string_to_py_%s" % type_identifier(self) + context = { + 'cname': cname, + 'type': self.typedef_cname, + } + from .UtilityCode import CythonUtilityCode + env.use_utility_code(CythonUtilityCode.load( + "string.to_py", "CppConvert.pyx", context=context)) + self.to_py_function = cname + return True if self.to_py_utility_code: env.use_utility_code(self.to_py_utility_code) return True @@ -474,62 +474,62 @@ class CTypedefType(BaseType): base_type = self.typedef_base_type if type(base_type) is CIntType: self.from_py_function = "__Pyx_PyInt_As_" + self.specialization_name() - env.use_utility_code(TempitaUtilityCode.load_cached( + env.use_utility_code(TempitaUtilityCode.load_cached( "CIntFromPy", "TypeConversion.c", - context={"TYPE": self.empty_declaration_code(), + context={"TYPE": self.empty_declaration_code(), "FROM_PY_FUNCTION": self.from_py_function})) return True elif base_type.is_float: pass # XXX implement! elif base_type.is_complex: pass # XXX implement! - elif base_type.is_cpp_string: - cname = '__pyx_convert_string_from_py_%s' % type_identifier(self) - context = { - 'cname': cname, - 'type': self.typedef_cname, - } - from .UtilityCode import CythonUtilityCode - env.use_utility_code(CythonUtilityCode.load( - "string.from_py", "CppConvert.pyx", context=context)) - self.from_py_function = cname - return True + elif base_type.is_cpp_string: + cname = '__pyx_convert_string_from_py_%s' % type_identifier(self) + context = { + 'cname': cname, + 'type': self.typedef_cname, + } + from .UtilityCode import CythonUtilityCode + env.use_utility_code(CythonUtilityCode.load( + "string.from_py", "CppConvert.pyx", context=context)) + self.from_py_function = cname + return True if self.from_py_utility_code: env.use_utility_code(self.from_py_utility_code) return True # delegation return self.typedef_base_type.create_from_py_utility_code(env) - def to_py_call_code(self, source_code, result_code, result_type, to_py_function=None): - if to_py_function is None: - to_py_function = self.to_py_function - return self.typedef_base_type.to_py_call_code( - source_code, result_code, result_type, to_py_function) - - def from_py_call_code(self, source_code, result_code, error_pos, code, - from_py_function=None, error_condition=None): - return self.typedef_base_type.from_py_call_code( + def to_py_call_code(self, source_code, result_code, result_type, to_py_function=None): + if to_py_function is None: + to_py_function = self.to_py_function + return self.typedef_base_type.to_py_call_code( + source_code, result_code, result_type, to_py_function) + + def from_py_call_code(self, source_code, result_code, error_pos, code, + from_py_function=None, error_condition=None): + return self.typedef_base_type.from_py_call_code( source_code, result_code, error_pos, code, from_py_function or self.from_py_function, error_condition or self.error_condition(result_code) ) - + def overflow_check_binop(self, binop, env, const_rhs=False): env.use_utility_code(UtilityCode.load("Common", "Overflow.c")) - type = self.empty_declaration_code() + type = self.empty_declaration_code() name = self.specialization_name() if binop == "lshift": - env.use_utility_code(TempitaUtilityCode.load_cached( + env.use_utility_code(TempitaUtilityCode.load_cached( "LeftShift", "Overflow.c", context={'TYPE': type, 'NAME': name, 'SIGNED': self.signed})) else: if const_rhs: binop += "_const" _load_overflow_base(env) - env.use_utility_code(TempitaUtilityCode.load_cached( + env.use_utility_code(TempitaUtilityCode.load_cached( "SizeCheck", "Overflow.c", context={'TYPE': type, 'NAME': name})) - env.use_utility_code(TempitaUtilityCode.load_cached( + env.use_utility_code(TempitaUtilityCode.load_cached( "Binop", "Overflow.c", context={'TYPE': type, 'NAME': name, 'BINOP': binop})) return "__Pyx_%s_%s_checking_overflow" % (binop, name) @@ -537,8 +537,8 @@ class CTypedefType(BaseType): def error_condition(self, result_code): if self.typedef_is_external: if self.exception_value: - condition = "(%s == %s)" % ( - result_code, self.cast_code(self.exception_value)) + condition = "(%s == %s)" % ( + result_code, self.cast_code(self.exception_value)) if self.exception_check: condition += " && PyErr_Occurred()" return condition @@ -594,9 +594,9 @@ class MemoryViewSliceType(PyrexType): the packing specifiers specify how the array elements are layed-out in memory. - 'contig' -- The data is contiguous in memory along this dimension. + 'contig' -- The data is contiguous in memory along this dimension. At most one dimension may be specified as 'contig'. - 'strided' -- The data isn't contiguous along this dimension. + 'strided' -- The data isn't contiguous along this dimension. 'follow' -- Used for C/Fortran contiguous arrays, a 'follow' dimension has its stride automatically computed from extents of the other dimensions to ensure C or Fortran memory layout. @@ -608,7 +608,7 @@ class MemoryViewSliceType(PyrexType): the *first* axis' packing spec and 'follow' for all other packing specs. """ - from . import Buffer, MemoryView + from . import Buffer, MemoryView self.dtype = base_dtype self.axes = axes @@ -622,17 +622,17 @@ class MemoryViewSliceType(PyrexType): self.writable_needed = False if not self.dtype.is_fused: - self.dtype_name = Buffer.mangle_dtype_name(self.dtype) - - def __hash__(self): - return hash(self.__class__) ^ hash(self.dtype) ^ hash(tuple(self.axes)) - - def __eq__(self, other): - if isinstance(other, BaseType): - return self.same_as_resolved_type(other) - else: - return False - + self.dtype_name = Buffer.mangle_dtype_name(self.dtype) + + def __hash__(self): + return hash(self.__class__) ^ hash(self.dtype) ^ hash(tuple(self.axes)) + + def __eq__(self, other): + if isinstance(other, BaseType): + return self.same_as_resolved_type(other) + else: + return False + def same_as_resolved_type(self, other_type): return ((other_type.is_memoryviewslice and #self.writable_needed == other_type.writable_needed and # FIXME: should be only uni-directional @@ -653,9 +653,9 @@ class MemoryViewSliceType(PyrexType): assert not pyrex assert not dll_linkage from . import MemoryView - base_code = str(self) if for_display else MemoryView.memviewslice_cname + base_code = str(self) if for_display else MemoryView.memviewslice_cname return self.base_declaration_code( - base_code, + base_code, entity_code) def attributes_known(self): @@ -707,33 +707,33 @@ class MemoryViewSliceType(PyrexType): elif attribute in ("copy", "copy_fortran"): ndim = len(self.axes) - follow_dim = [('direct', 'follow')] - contig_dim = [('direct', 'contig')] - to_axes_c = follow_dim * (ndim - 1) + contig_dim - to_axes_f = contig_dim + follow_dim * (ndim -1) + follow_dim = [('direct', 'follow')] + contig_dim = [('direct', 'contig')] + to_axes_c = follow_dim * (ndim - 1) + contig_dim + to_axes_f = contig_dim + follow_dim * (ndim -1) + + dtype = self.dtype + if dtype.is_const: + dtype = dtype.const_base_type - dtype = self.dtype - if dtype.is_const: - dtype = dtype.const_base_type + to_memview_c = MemoryViewSliceType(dtype, to_axes_c) + to_memview_f = MemoryViewSliceType(dtype, to_axes_f) - to_memview_c = MemoryViewSliceType(dtype, to_axes_c) - to_memview_f = MemoryViewSliceType(dtype, to_axes_f) - for to_memview, cython_name in [(to_memview_c, "copy"), (to_memview_f, "copy_fortran")]: - copy_func_type = CFuncType( - to_memview, - [CFuncTypeArg("memviewslice", self, None)]) - copy_cname = MemoryView.copy_c_or_fortran_cname(to_memview) - - entry = scope.declare_cfunction( - cython_name, - copy_func_type, pos=pos, defining=1, - cname=copy_cname) - - utility = MemoryView.get_copy_new_utility(pos, self, to_memview) - env.use_utility_code(utility) - + copy_func_type = CFuncType( + to_memview, + [CFuncTypeArg("memviewslice", self, None)]) + copy_cname = MemoryView.copy_c_or_fortran_cname(to_memview) + + entry = scope.declare_cfunction( + cython_name, + copy_func_type, pos=pos, defining=1, + cname=copy_cname) + + utility = MemoryView.get_copy_new_utility(pos, self, to_memview) + env.use_utility_code(utility) + MemoryView.use_cython_array_utility_code(env) elif attribute in ("is_c_contig", "is_f_contig"): @@ -758,35 +758,35 @@ class MemoryViewSliceType(PyrexType): return True - def get_entry(self, node, cname=None, type=None): - from . import MemoryView, Symtab - - if cname is None: - assert node.is_simple() or node.is_temp or node.is_elemental - cname = node.result() - - if type is None: - type = node.type - - entry = Symtab.Entry(cname, cname, type, node.pos) - return MemoryView.MemoryViewSliceBufferEntry(entry) - - def conforms_to(self, dst, broadcast=False, copying=False): - """ - Returns True if src conforms to dst, False otherwise. - - If conformable, the types are the same, the ndims are equal, and each axis spec is conformable. - - Any packing/access spec is conformable to itself. - - 'direct' and 'ptr' are conformable to 'full'. - 'contig' and 'follow' are conformable to 'strided'. - Any other combo is not conformable. - """ - from . import MemoryView - - src = self - + def get_entry(self, node, cname=None, type=None): + from . import MemoryView, Symtab + + if cname is None: + assert node.is_simple() or node.is_temp or node.is_elemental + cname = node.result() + + if type is None: + type = node.type + + entry = Symtab.Entry(cname, cname, type, node.pos) + return MemoryView.MemoryViewSliceBufferEntry(entry) + + def conforms_to(self, dst, broadcast=False, copying=False): + """ + Returns True if src conforms to dst, False otherwise. + + If conformable, the types are the same, the ndims are equal, and each axis spec is conformable. + + Any packing/access spec is conformable to itself. + + 'direct' and 'ptr' are conformable to 'full'. + 'contig' and 'follow' are conformable to 'strided'. + Any other combo is not conformable. + """ + from . import MemoryView + + src = self + #if not copying and self.writable_needed and not dst.writable_needed: # return False @@ -802,73 +802,73 @@ class MemoryViewSliceType(PyrexType): src_dtype = src_dtype.const_base_type if src_dtype != dst_dtype: - return False - - if src.ndim != dst.ndim: - if broadcast: - src, dst = MemoryView.broadcast_types(src, dst) - else: - return False - - for src_spec, dst_spec in zip(src.axes, dst.axes): - src_access, src_packing = src_spec - dst_access, dst_packing = dst_spec - if src_access != dst_access and dst_access != 'full': - return False - if src_packing != dst_packing and dst_packing != 'strided' and not copying: - return False - - return True - - def valid_dtype(self, dtype, i=0): - """ - Return whether type dtype can be used as the base type of a - memoryview slice. - - We support structs, numeric types and objects - """ - if dtype.is_complex and dtype.real_type.is_int: - return False - - if dtype.is_struct and dtype.kind == 'struct': - for member in dtype.scope.var_entries: - if not self.valid_dtype(member.type): - return False - - return True - - return ( - dtype.is_error or - # Pointers are not valid (yet) - # (dtype.is_ptr and valid_memslice_dtype(dtype.base_type)) or - (dtype.is_array and i < 8 and self.valid_dtype(dtype.base_type, i + 1)) or - dtype.is_numeric or - dtype.is_pyobject or - dtype.is_fused or # accept this as it will be replaced by specializations later - (dtype.is_typedef and self.valid_dtype(dtype.typedef_base_type)) - ) - - def validate_memslice_dtype(self, pos): - if not self.valid_dtype(self.dtype): - error(pos, "Invalid base type for memoryview slice: %s" % self.dtype) - - def assert_direct_dims(self, pos): - for access, packing in self.axes: - if access != 'direct': - error(pos, "All dimensions must be direct") - return False - return True - - def transpose(self, pos): - if not self.assert_direct_dims(pos): - return error_type - return MemoryViewSliceType(self.dtype, self.axes[::-1]) - - def specialization_name(self): - return '%s_%s' % ( - super(MemoryViewSliceType,self).specialization_name(), - self.specialization_suffix()) - + return False + + if src.ndim != dst.ndim: + if broadcast: + src, dst = MemoryView.broadcast_types(src, dst) + else: + return False + + for src_spec, dst_spec in zip(src.axes, dst.axes): + src_access, src_packing = src_spec + dst_access, dst_packing = dst_spec + if src_access != dst_access and dst_access != 'full': + return False + if src_packing != dst_packing and dst_packing != 'strided' and not copying: + return False + + return True + + def valid_dtype(self, dtype, i=0): + """ + Return whether type dtype can be used as the base type of a + memoryview slice. + + We support structs, numeric types and objects + """ + if dtype.is_complex and dtype.real_type.is_int: + return False + + if dtype.is_struct and dtype.kind == 'struct': + for member in dtype.scope.var_entries: + if not self.valid_dtype(member.type): + return False + + return True + + return ( + dtype.is_error or + # Pointers are not valid (yet) + # (dtype.is_ptr and valid_memslice_dtype(dtype.base_type)) or + (dtype.is_array and i < 8 and self.valid_dtype(dtype.base_type, i + 1)) or + dtype.is_numeric or + dtype.is_pyobject or + dtype.is_fused or # accept this as it will be replaced by specializations later + (dtype.is_typedef and self.valid_dtype(dtype.typedef_base_type)) + ) + + def validate_memslice_dtype(self, pos): + if not self.valid_dtype(self.dtype): + error(pos, "Invalid base type for memoryview slice: %s" % self.dtype) + + def assert_direct_dims(self, pos): + for access, packing in self.axes: + if access != 'direct': + error(pos, "All dimensions must be direct") + return False + return True + + def transpose(self, pos): + if not self.assert_direct_dims(pos): + return error_type + return MemoryViewSliceType(self.dtype, self.axes[::-1]) + + def specialization_name(self): + return '%s_%s' % ( + super(MemoryViewSliceType,self).specialization_name(), + self.specialization_suffix()) + def specialization_suffix(self): return "%s_%s" % (self.axes_to_name(), self.dtype_name) @@ -886,9 +886,9 @@ class MemoryViewSliceType(PyrexType): # We don't have 'code', so use a LazyUtilityCode with a callback. def lazy_utility_callback(code): - context['dtype_typeinfo'] = Buffer.get_type_information_cname(code, self.dtype) + context['dtype_typeinfo'] = Buffer.get_type_information_cname(code, self.dtype) return TempitaUtilityCode.load( - "ObjectToMemviewSlice", "MemoryView_C.c", context=context) + "ObjectToMemviewSlice", "MemoryView_C.c", context=context) env.use_utility_code(MemoryView.memviewslice_init_code) env.use_utility_code(LazyUtilityCode(lazy_utility_callback)) @@ -908,7 +908,7 @@ class MemoryViewSliceType(PyrexType): buf_flag = self.flags, ndim = self.ndim, axes_specs = ', '.join(self.axes_to_code()), - dtype_typedecl = self.dtype.empty_declaration_code(), + dtype_typedecl = self.dtype.empty_declaration_code(), struct_nesting_depth = self.dtype.struct_nesting_depth(), c_or_f_flag = c_or_f_flag, funcname = funcname, @@ -917,29 +917,29 @@ class MemoryViewSliceType(PyrexType): self.from_py_function = funcname return True - def from_py_call_code(self, source_code, result_code, error_pos, code, - from_py_function=None, error_condition=None): + def from_py_call_code(self, source_code, result_code, error_pos, code, + from_py_function=None, error_condition=None): # NOTE: auto-detection of readonly buffers is disabled: # writable = self.writable_needed or not self.dtype.is_const writable = not self.dtype.is_const return self._assign_from_py_code( source_code, result_code, error_pos, code, from_py_function, error_condition, extra_args=['PyBUF_WRITABLE' if writable else '0']) - + def create_to_py_utility_code(self, env): - self._dtype_to_py_func, self._dtype_from_py_func = self.dtype_object_conversion_funcs(env) + self._dtype_to_py_func, self._dtype_from_py_func = self.dtype_object_conversion_funcs(env) return True - def to_py_call_code(self, source_code, result_code, result_type, to_py_function=None): - assert self._dtype_to_py_func - assert self._dtype_from_py_func + def to_py_call_code(self, source_code, result_code, result_type, to_py_function=None): + assert self._dtype_to_py_func + assert self._dtype_from_py_func + + to_py_func = "(PyObject *(*)(char *)) " + self._dtype_to_py_func + from_py_func = "(int (*)(char *, PyObject *)) " + self._dtype_from_py_func - to_py_func = "(PyObject *(*)(char *)) " + self._dtype_to_py_func - from_py_func = "(int (*)(char *, PyObject *)) " + self._dtype_from_py_func + tup = (result_code, source_code, self.ndim, to_py_func, from_py_func, self.dtype.is_pyobject) + return "%s = __pyx_memoryview_fromslice(%s, %s, %s, %s, %d);" % tup - tup = (result_code, source_code, self.ndim, to_py_func, from_py_func, self.dtype.is_pyobject) - return "%s = __pyx_memoryview_fromslice(%s, %s, %s, %s, %d);" % tup - def dtype_object_conversion_funcs(self, env): get_function = "__pyx_memview_get_%s" % self.dtype_name set_function = "__pyx_memview_set_%s" % self.dtype_name @@ -977,8 +977,8 @@ class MemoryViewSliceType(PyrexType): error_condition=error_condition, ) - utility = TempitaUtilityCode.load_cached( - utility_name, "MemoryView_C.c", context=context) + utility = TempitaUtilityCode.load_cached( + utility_name, "MemoryView_C.c", context=context) env.use_utility_code(utility) return get_function, set_function @@ -1061,9 +1061,9 @@ class BufferType(BaseType): self.cast = cast self.is_numpy_buffer = self.base.name == "ndarray" - def can_coerce_to_pyobject(self,env): - return True - + def can_coerce_to_pyobject(self,env): + return True + def can_coerce_from_pyobject(self,env): return True @@ -1077,11 +1077,11 @@ class BufferType(BaseType): self.negative_indices, self.cast) return self - def get_entry(self, node): - from . import Buffer - assert node.is_name - return Buffer.BufferEntry(node.entry) - + def get_entry(self, node): + from . import Buffer + assert node.is_name + return Buffer.BufferEntry(node.entry) + def __getattr__(self, name): return getattr(self.base, name) @@ -1195,7 +1195,7 @@ class BuiltinObjectType(PyObjectType): has_attributes = 1 base_type = None module_name = '__builtin__' - require_exact = 1 + require_exact = 1 # fields that let it look like an extension type vtabslot_cname = None @@ -1203,7 +1203,7 @@ class BuiltinObjectType(PyObjectType): vtabptr_cname = None typedef_flag = True is_external = True - decl_type = 'PyObject' + decl_type = 'PyObject' def __init__(self, name, cname, objstruct_cname=None): self.name = name @@ -1211,12 +1211,12 @@ class BuiltinObjectType(PyObjectType): self.typeptr_cname = "(&%s)" % cname self.objstruct_cname = objstruct_cname self.is_gc_simple = name in builtin_types_that_cannot_create_refcycles - if name == 'type': - # Special case the type type, as many C API calls (and other - # libraries) actually expect a PyTypeObject* for type arguments. - self.decl_type = objstruct_cname - if name == 'Exception': - self.require_exact = 0 + if name == 'type': + # Special case the type type, as many C API calls (and other + # libraries) actually expect a PyTypeObject* for type arguments. + self.decl_type = objstruct_cname + if name == 'Exception': + self.require_exact = 0 def set_scope(self, scope): self.scope = scope @@ -1270,15 +1270,15 @@ class BuiltinObjectType(PyObjectType): type_check = 'PyString_Check' elif type_name == 'basestring': type_check = '__Pyx_PyBaseString_Check' - elif type_name == 'Exception': - type_check = '__Pyx_PyException_Check' + elif type_name == 'Exception': + type_check = '__Pyx_PyException_Check' elif type_name == 'bytearray': type_check = 'PyByteArray_Check' elif type_name == 'frozenset': type_check = 'PyFrozenSet_Check' else: type_check = 'Py%s_Check' % type_name.capitalize() - if exact and type_name not in ('bool', 'slice', 'Exception'): + if exact and type_name not in ('bool', 'slice', 'Exception'): type_check += 'Exact' return type_check @@ -1306,19 +1306,19 @@ class BuiltinObjectType(PyObjectType): if pyrex or for_display: base_code = self.name else: - base_code = public_decl(self.decl_type, dll_linkage) + base_code = public_decl(self.decl_type, dll_linkage) entity_code = "*%s" % entity_code return self.base_declaration_code(base_code, entity_code) - def as_pyobject(self, cname): - if self.decl_type == 'PyObject': - return cname - else: - return "(PyObject *)" + cname - + def as_pyobject(self, cname): + if self.decl_type == 'PyObject': + return cname + else: + return "(PyObject *)" + cname + def cast_code(self, expr_code, to_object_struct = False): return "((%s*)%s)" % ( - to_object_struct and self.objstruct_cname or self.decl_type, # self.objstruct_cname may be None + to_object_struct and self.objstruct_cname or self.decl_type, # self.objstruct_cname may be None expr_code) def py_type_name(self): @@ -1346,7 +1346,7 @@ class PyExtensionType(PyObjectType): # vtable_cname string Name of C method table definition # early_init boolean Whether to initialize early (as opposed to during module execution). # defered_declarations [thunk] Used to declare class hierarchies in order - # check_size 'warn', 'error', 'ignore' What to do if tp_basicsize does not match + # check_size 'warn', 'error', 'ignore' What to do if tp_basicsize does not match is_extension_type = 1 has_attributes = 1 @@ -1354,7 +1354,7 @@ class PyExtensionType(PyObjectType): objtypedef_cname = None - def __init__(self, name, typedef_flag, base_type, is_external=0, check_size=None): + def __init__(self, name, typedef_flag, base_type, is_external=0, check_size=None): self.name = name self.scope = None self.typedef_flag = typedef_flag @@ -1370,7 +1370,7 @@ class PyExtensionType(PyObjectType): self.vtabptr_cname = None self.vtable_cname = None self.is_external = is_external - self.check_size = check_size or 'warn' + self.check_size = check_size or 'warn' self.defered_declarations = [] def set_scope(self, scope): @@ -1494,31 +1494,31 @@ class CType(PyrexType): else: return 0 - def to_py_call_code(self, source_code, result_code, result_type, to_py_function=None): - func = self.to_py_function if to_py_function is None else to_py_function - assert func - if self.is_string or self.is_cpp_string: - if result_type.is_builtin_type: - result_type_name = result_type.name - if result_type_name in ('bytes', 'str', 'unicode'): - func = func.replace("Object", result_type_name.title(), 1) - elif result_type_name == 'bytearray': - func = func.replace("Object", "ByteArray", 1) - return '%s = %s(%s)' % ( - result_code, - func, - source_code or 'NULL') - - def from_py_call_code(self, source_code, result_code, error_pos, code, - from_py_function=None, error_condition=None): + def to_py_call_code(self, source_code, result_code, result_type, to_py_function=None): + func = self.to_py_function if to_py_function is None else to_py_function + assert func + if self.is_string or self.is_cpp_string: + if result_type.is_builtin_type: + result_type_name = result_type.name + if result_type_name in ('bytes', 'str', 'unicode'): + func = func.replace("Object", result_type_name.title(), 1) + elif result_type_name == 'bytearray': + func = func.replace("Object", "ByteArray", 1) + return '%s = %s(%s)' % ( + result_code, + func, + source_code or 'NULL') + + def from_py_call_code(self, source_code, result_code, error_pos, code, + from_py_function=None, error_condition=None): return self._assign_from_py_code( source_code, result_code, error_pos, code, from_py_function, error_condition) - + class PythranExpr(CType): # Pythran object of a given type - + to_py_function = "__Pyx_pythran_to_python" is_pythran_expr = True writable = True @@ -1576,10 +1576,10 @@ class CConstType(BaseType): def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0): - if for_display or pyrex: - return "const " + self.const_base_type.declaration_code(entity_code, for_display, dll_linkage, pyrex) - else: - return self.const_base_type.declaration_code("const %s" % entity_code, for_display, dll_linkage, pyrex) + if for_display or pyrex: + return "const " + self.const_base_type.declaration_code(entity_code, for_display, dll_linkage, pyrex) + else: + return self.const_base_type.declaration_code("const %s" % entity_code, for_display, dll_linkage, pyrex) def specialize(self, values): base_type = self.const_base_type.specialize(values) @@ -1591,9 +1591,9 @@ class CConstType(BaseType): def deduce_template_params(self, actual): return self.const_base_type.deduce_template_params(actual) - def can_coerce_to_pyobject(self, env): - return self.const_base_type.can_coerce_to_pyobject(env) - + def can_coerce_to_pyobject(self, env): + return self.const_base_type.can_coerce_to_pyobject(env) + def can_coerce_from_pyobject(self, env): return self.const_base_type.can_coerce_from_pyobject(env) @@ -1628,17 +1628,17 @@ class FusedType(CType): exception_check = 0 def __init__(self, types, name=None): - # Use list rather than set to preserve order (list should be short). - flattened_types = [] - for t in types: - if t.is_fused: - # recursively merge in subtypes - for subtype in t.types: - if subtype not in flattened_types: - flattened_types.append(subtype) - elif t not in flattened_types: - flattened_types.append(t) - self.types = flattened_types + # Use list rather than set to preserve order (list should be short). + flattened_types = [] + for t in types: + if t.is_fused: + # recursively merge in subtypes + for subtype in t.types: + if subtype not in flattened_types: + flattened_types.append(subtype) + elif t not in flattened_types: + flattened_types.append(t) + self.types = flattened_types self.name = name def declaration_code(self, entity_code, for_display = 0, @@ -1669,7 +1669,7 @@ class CVoidType(CType): # is_void = 1 - to_py_function = "__Pyx_void_to_None" + to_py_function = "__Pyx_void_to_None" def __repr__(self): return "<CVoidType>" @@ -1716,10 +1716,10 @@ class CNumericType(CType): def __init__(self, rank, signed = 1): self.rank = rank - if rank > 0 and signed == SIGNED: - # Signed is meaningless for anything but char, and complicates - # type promotion. - signed = 1 + if rank > 0 and signed == SIGNED: + # Signed is meaningless for anything but char, and complicates + # type promotion. + signed = 1 self.signed = signed def sign_and_name(self): @@ -1783,12 +1783,12 @@ class CIntLike(object): """ to_py_function = None from_py_function = None - to_pyunicode_utility = None - default_format_spec = 'd' + to_pyunicode_utility = None + default_format_spec = 'd' + + def can_coerce_to_pyobject(self, env): + return True - def can_coerce_to_pyobject(self, env): - return True - def can_coerce_from_pyobject(self, env): return True @@ -1810,48 +1810,48 @@ class CIntLike(object): "FROM_PY_FUNCTION": self.from_py_function})) return True - @staticmethod - def _parse_format(format_spec): - padding = ' ' - if not format_spec: - return ('d', 0, padding) - format_type = format_spec[-1] - if format_type in ('o', 'd', 'x', 'X'): - prefix = format_spec[:-1] - elif format_type.isdigit(): - format_type = 'd' - prefix = format_spec - else: - return (None, 0, padding) - if not prefix: - return (format_type, 0, padding) - if prefix[0] == '-': - prefix = prefix[1:] - if prefix and prefix[0] == '0': - padding = '0' - prefix = prefix.lstrip('0') - if prefix.isdigit(): - return (format_type, int(prefix), padding) - return (None, 0, padding) - - def can_coerce_to_pystring(self, env, format_spec=None): - format_type, width, padding = self._parse_format(format_spec) - return format_type is not None and width <= 2**30 - - def convert_to_pystring(self, cvalue, code, format_spec=None): - if self.to_pyunicode_utility is None: - utility_code_name = "__Pyx_PyUnicode_From_" + self.specialization_name() - to_pyunicode_utility = TempitaUtilityCode.load_cached( - "CIntToPyUnicode", "TypeConversion.c", - context={"TYPE": self.empty_declaration_code(), - "TO_PY_FUNCTION": utility_code_name}) - self.to_pyunicode_utility = (utility_code_name, to_pyunicode_utility) - else: - utility_code_name, to_pyunicode_utility = self.to_pyunicode_utility - code.globalstate.use_utility_code(to_pyunicode_utility) - format_type, width, padding_char = self._parse_format(format_spec) - return "%s(%s, %d, '%s', '%s')" % (utility_code_name, cvalue, width, padding_char, format_type) - + @staticmethod + def _parse_format(format_spec): + padding = ' ' + if not format_spec: + return ('d', 0, padding) + format_type = format_spec[-1] + if format_type in ('o', 'd', 'x', 'X'): + prefix = format_spec[:-1] + elif format_type.isdigit(): + format_type = 'd' + prefix = format_spec + else: + return (None, 0, padding) + if not prefix: + return (format_type, 0, padding) + if prefix[0] == '-': + prefix = prefix[1:] + if prefix and prefix[0] == '0': + padding = '0' + prefix = prefix.lstrip('0') + if prefix.isdigit(): + return (format_type, int(prefix), padding) + return (None, 0, padding) + + def can_coerce_to_pystring(self, env, format_spec=None): + format_type, width, padding = self._parse_format(format_spec) + return format_type is not None and width <= 2**30 + + def convert_to_pystring(self, cvalue, code, format_spec=None): + if self.to_pyunicode_utility is None: + utility_code_name = "__Pyx_PyUnicode_From_" + self.specialization_name() + to_pyunicode_utility = TempitaUtilityCode.load_cached( + "CIntToPyUnicode", "TypeConversion.c", + context={"TYPE": self.empty_declaration_code(), + "TO_PY_FUNCTION": utility_code_name}) + self.to_pyunicode_utility = (utility_code_name, to_pyunicode_utility) + else: + utility_code_name, to_pyunicode_utility = self.to_pyunicode_utility + code.globalstate.use_utility_code(to_pyunicode_utility) + format_type, width, padding_char = self._parse_format(format_spec) + return "%s(%s, %d, '%s', '%s')" % (utility_code_name, cvalue, width, padding_char, format_type) + class CIntType(CIntLike, CNumericType): @@ -1890,21 +1890,21 @@ class CIntType(CIntLike, CNumericType): def overflow_check_binop(self, binop, env, const_rhs=False): env.use_utility_code(UtilityCode.load("Common", "Overflow.c")) - type = self.empty_declaration_code() + type = self.empty_declaration_code() name = self.specialization_name() if binop == "lshift": - env.use_utility_code(TempitaUtilityCode.load_cached( + env.use_utility_code(TempitaUtilityCode.load_cached( "LeftShift", "Overflow.c", context={'TYPE': type, 'NAME': name, 'SIGNED': self.signed})) else: if const_rhs: binop += "_const" if type in ('int', 'long', 'long long'): - env.use_utility_code(TempitaUtilityCode.load_cached( + env.use_utility_code(TempitaUtilityCode.load_cached( "BaseCaseSigned", "Overflow.c", context={'INT': type, 'NAME': name})) elif type in ('unsigned int', 'unsigned long', 'unsigned long long'): - env.use_utility_code(TempitaUtilityCode.load_cached( + env.use_utility_code(TempitaUtilityCode.load_cached( "BaseCaseUnsigned", "Overflow.c", context={'UINT': type, 'NAME': name})) elif self.rank <= 1: @@ -1912,23 +1912,23 @@ class CIntType(CIntLike, CNumericType): return "__Pyx_%s_%s_no_overflow" % (binop, name) else: _load_overflow_base(env) - env.use_utility_code(TempitaUtilityCode.load_cached( + env.use_utility_code(TempitaUtilityCode.load_cached( "SizeCheck", "Overflow.c", context={'TYPE': type, 'NAME': name})) - env.use_utility_code(TempitaUtilityCode.load_cached( + env.use_utility_code(TempitaUtilityCode.load_cached( "Binop", "Overflow.c", context={'TYPE': type, 'NAME': name, 'BINOP': binop})) return "__Pyx_%s_%s_checking_overflow" % (binop, name) - + def _load_overflow_base(env): env.use_utility_code(UtilityCode.load("Common", "Overflow.c")) for type in ('int', 'long', 'long long'): - env.use_utility_code(TempitaUtilityCode.load_cached( + env.use_utility_code(TempitaUtilityCode.load_cached( "BaseCaseSigned", "Overflow.c", context={'INT': type, 'NAME': type.replace(' ', '_')})) for type in ('unsigned int', 'unsigned long', 'unsigned long long'): - env.use_utility_code(TempitaUtilityCode.load_cached( + env.use_utility_code(TempitaUtilityCode.load_cached( "BaseCaseUnsigned", "Overflow.c", context={'UINT': type, 'NAME': type.replace(' ', '_')})) @@ -1947,45 +1947,45 @@ class CReturnCodeType(CIntType): is_returncode = True exception_check = False - default_format_spec = '' + default_format_spec = '' + + def can_coerce_to_pystring(self, env, format_spec=None): + return not format_spec + + def convert_to_pystring(self, cvalue, code, format_spec=None): + return "__Pyx_NewRef(%s)" % code.globalstate.get_py_string_const(StringEncoding.EncodedString("None")).cname - def can_coerce_to_pystring(self, env, format_spec=None): - return not format_spec - def convert_to_pystring(self, cvalue, code, format_spec=None): - return "__Pyx_NewRef(%s)" % code.globalstate.get_py_string_const(StringEncoding.EncodedString("None")).cname - - class CBIntType(CIntType): to_py_function = "__Pyx_PyBool_FromLong" from_py_function = "__Pyx_PyObject_IsTrue" - exception_check = 1 # for C++ bool - default_format_spec = '' - - def can_coerce_to_pystring(self, env, format_spec=None): - return not format_spec or super(CBIntType, self).can_coerce_to_pystring(env, format_spec) - - def convert_to_pystring(self, cvalue, code, format_spec=None): - if format_spec: - return super(CBIntType, self).convert_to_pystring(cvalue, code, format_spec) - # NOTE: no caching here as the string constant cnames depend on the current module - utility_code_name = "__Pyx_PyUnicode_FromBInt_" + self.specialization_name() - to_pyunicode_utility = TempitaUtilityCode.load_cached( - "CBIntToPyUnicode", "TypeConversion.c", context={ - "TRUE_CONST": code.globalstate.get_py_string_const(StringEncoding.EncodedString("True")).cname, - "FALSE_CONST": code.globalstate.get_py_string_const(StringEncoding.EncodedString("False")).cname, - "TO_PY_FUNCTION": utility_code_name, - }) - code.globalstate.use_utility_code(to_pyunicode_utility) - return "%s(%s)" % (utility_code_name, cvalue) - + exception_check = 1 # for C++ bool + default_format_spec = '' + + def can_coerce_to_pystring(self, env, format_spec=None): + return not format_spec or super(CBIntType, self).can_coerce_to_pystring(env, format_spec) + + def convert_to_pystring(self, cvalue, code, format_spec=None): + if format_spec: + return super(CBIntType, self).convert_to_pystring(cvalue, code, format_spec) + # NOTE: no caching here as the string constant cnames depend on the current module + utility_code_name = "__Pyx_PyUnicode_FromBInt_" + self.specialization_name() + to_pyunicode_utility = TempitaUtilityCode.load_cached( + "CBIntToPyUnicode", "TypeConversion.c", context={ + "TRUE_CONST": code.globalstate.get_py_string_const(StringEncoding.EncodedString("True")).cname, + "FALSE_CONST": code.globalstate.get_py_string_const(StringEncoding.EncodedString("False")).cname, + "TO_PY_FUNCTION": utility_code_name, + }) + code.globalstate.use_utility_code(to_pyunicode_utility) + return "%s(%s)" % (utility_code_name, cvalue) + def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0): - if for_display: + if for_display: base_code = 'bool' - elif pyrex: - base_code = 'bint' + elif pyrex: + base_code = 'bint' else: base_code = public_decl('int', dll_linkage) return self.base_declaration_code(base_code, entity_code) @@ -2014,9 +2014,9 @@ class CPyUCS4IntType(CIntType): to_py_function = "PyUnicode_FromOrdinal" from_py_function = "__Pyx_PyObject_AsPy_UCS4" - def can_coerce_to_pystring(self, env, format_spec=None): - return False # does the right thing anyway - + def can_coerce_to_pystring(self, env, format_spec=None): + return False # does the right thing anyway + def create_from_py_utility_code(self, env): env.use_utility_code(UtilityCode.load_cached("ObjectAsUCS4", "TypeConversion.c")) return True @@ -2038,9 +2038,9 @@ class CPyUnicodeIntType(CIntType): to_py_function = "PyUnicode_FromOrdinal" from_py_function = "__Pyx_PyObject_AsPy_UNICODE" - def can_coerce_to_pystring(self, env, format_spec=None): - return False # does the right thing anyway - + def can_coerce_to_pystring(self, env, format_spec=None): + return False # does the right thing anyway + def create_from_py_utility_code(self, env): env.use_utility_code(UtilityCode.load_cached("ObjectAsPyUnicode", "TypeConversion.c")) return True @@ -2116,11 +2116,11 @@ class CComplexType(CNumericType): def __init__(self, real_type): while real_type.is_typedef and not real_type.typedef_is_external: real_type = real_type.typedef_base_type - self.funcsuffix = "_%s" % real_type.specialization_name() - if real_type.is_float: - self.math_h_modifier = real_type.math_h_modifier + self.funcsuffix = "_%s" % real_type.specialization_name() + if real_type.is_float: + self.math_h_modifier = real_type.math_h_modifier else: - self.math_h_modifier = "_UNUSED" + self.math_h_modifier = "_UNUSED" self.real_type = real_type CNumericType.__init__(self, real_type.rank + 0.5, real_type.signed) @@ -2201,40 +2201,40 @@ class CComplexType(CNumericType): return True - def _utility_code_context(self): - return { - 'type': self.empty_declaration_code(), - 'type_name': self.specialization_name(), - 'real_type': self.real_type.empty_declaration_code(), - 'func_suffix': self.funcsuffix, - 'm': self.math_h_modifier, - 'is_float': int(self.real_type.is_float) - } - + def _utility_code_context(self): + return { + 'type': self.empty_declaration_code(), + 'type_name': self.specialization_name(), + 'real_type': self.real_type.empty_declaration_code(), + 'func_suffix': self.funcsuffix, + 'm': self.math_h_modifier, + 'is_float': int(self.real_type.is_float) + } + def create_declaration_utility_code(self, env): # This must always be run, because a single CComplexType instance can be shared # across multiple compilations (the one created in the module scope) - env.use_utility_code(UtilityCode.load_cached('Header', 'Complex.c')) - env.use_utility_code(UtilityCode.load_cached('RealImag', 'Complex.c')) - env.use_utility_code(TempitaUtilityCode.load_cached( - 'Declarations', 'Complex.c', self._utility_code_context())) - env.use_utility_code(TempitaUtilityCode.load_cached( - 'Arithmetic', 'Complex.c', self._utility_code_context())) + env.use_utility_code(UtilityCode.load_cached('Header', 'Complex.c')) + env.use_utility_code(UtilityCode.load_cached('RealImag', 'Complex.c')) + env.use_utility_code(TempitaUtilityCode.load_cached( + 'Declarations', 'Complex.c', self._utility_code_context())) + env.use_utility_code(TempitaUtilityCode.load_cached( + 'Arithmetic', 'Complex.c', self._utility_code_context())) + return True + + def can_coerce_to_pyobject(self, env): return True - def can_coerce_to_pyobject(self, env): - return True - def can_coerce_from_pyobject(self, env): return True def create_to_py_utility_code(self, env): - env.use_utility_code(UtilityCode.load_cached('ToPy', 'Complex.c')) + env.use_utility_code(UtilityCode.load_cached('ToPy', 'Complex.c')) return True def create_from_py_utility_code(self, env): - env.use_utility_code(TempitaUtilityCode.load_cached( - 'FromPy', 'Complex.c', self._utility_code_context())) + env.use_utility_code(TempitaUtilityCode.load_cached( + 'FromPy', 'Complex.c', self._utility_code_context())) self.from_py_function = "__Pyx_PyComplex_As_" + self.specialization_name() return True @@ -2269,7 +2269,7 @@ complex_ops = { (2, '-'): 'diff', (2, '*'): 'prod', (2, '/'): 'quot', - (2, '**'): 'pow', + (2, '**'): 'pow', (2, '=='): 'eq', } @@ -2302,8 +2302,8 @@ class CPointerBaseType(CType): def __init__(self, base_type): self.base_type = base_type - if base_type.is_const: - base_type = base_type.const_base_type + if base_type.is_const: + base_type = base_type.const_base_type for char_type in (c_char_type, c_uchar_type, c_schar_type): if base_type.same_as(char_type): self.is_string = 1 @@ -2313,16 +2313,16 @@ class CPointerBaseType(CType): self.is_pyunicode_ptr = 1 if self.is_string and not base_type.is_error: - if base_type.signed == 2: - self.to_py_function = "__Pyx_PyObject_FromCString" - if self.is_ptr: + if base_type.signed == 2: + self.to_py_function = "__Pyx_PyObject_FromCString" + if self.is_ptr: self.from_py_function = "__Pyx_PyObject_As%sSString" - elif base_type.signed: + elif base_type.signed: self.to_py_function = "__Pyx_PyObject_FromString" if self.is_ptr: self.from_py_function = "__Pyx_PyObject_As%sString" else: - self.to_py_function = "__Pyx_PyObject_FromCString" + self.to_py_function = "__Pyx_PyObject_FromCString" if self.is_ptr: self.from_py_function = "__Pyx_PyObject_As%sUString" if self.is_ptr: @@ -2353,7 +2353,7 @@ class CArrayType(CPointerBaseType): # size integer or None Number of elements is_array = 1 - to_tuple_function = None + to_tuple_function = None def __init__(self, base_type, size): super(CArrayType, self).__init__(base_type) @@ -2376,12 +2376,12 @@ class CArrayType(CPointerBaseType): or other_type is error_type) def assignable_from_resolved_type(self, src_type): - # C arrays are assigned by value, either Python containers or C arrays/pointers - if src_type.is_pyobject: - return True - if src_type.is_ptr or src_type.is_array: - return self.base_type.assignable_from(src_type.base_type) - return False + # C arrays are assigned by value, either Python containers or C arrays/pointers + if src_type.is_pyobject: + return True + if src_type.is_ptr or src_type.is_array: + return self.base_type.assignable_from(src_type.base_type) + return False def element_ptr_type(self): return c_ptr_type(self.base_type) @@ -2409,7 +2409,7 @@ class CArrayType(CPointerBaseType): if base_type == self.base_type: return self else: - return CArrayType(base_type, self.size) + return CArrayType(base_type, self.size) def deduce_template_params(self, actual): if isinstance(actual, CArrayType): @@ -2417,79 +2417,79 @@ class CArrayType(CPointerBaseType): else: return {} - def can_coerce_to_pyobject(self, env): - return self.base_type.can_coerce_to_pyobject(env) + def can_coerce_to_pyobject(self, env): + return self.base_type.can_coerce_to_pyobject(env) def can_coerce_from_pyobject(self, env): return self.base_type.can_coerce_from_pyobject(env) - def create_to_py_utility_code(self, env): - if self.to_py_function is not None: - return self.to_py_function - if not self.base_type.create_to_py_utility_code(env): - return False - + def create_to_py_utility_code(self, env): + if self.to_py_function is not None: + return self.to_py_function + if not self.base_type.create_to_py_utility_code(env): + return False + safe_typename = self.base_type.specialization_name() - to_py_function = "__Pyx_carray_to_py_%s" % safe_typename - to_tuple_function = "__Pyx_carray_to_tuple_%s" % safe_typename - - from .UtilityCode import CythonUtilityCode - context = { - 'cname': to_py_function, - 'to_tuple_cname': to_tuple_function, + to_py_function = "__Pyx_carray_to_py_%s" % safe_typename + to_tuple_function = "__Pyx_carray_to_tuple_%s" % safe_typename + + from .UtilityCode import CythonUtilityCode + context = { + 'cname': to_py_function, + 'to_tuple_cname': to_tuple_function, 'base_type': self.base_type, - } - env.use_utility_code(CythonUtilityCode.load( - "carray.to_py", "CConvert.pyx", - outer_module_scope=env.global_scope(), # need access to types declared in module - context=context, compiler_directives=dict(env.global_scope().directives))) - self.to_tuple_function = to_tuple_function - self.to_py_function = to_py_function - return True - - def to_py_call_code(self, source_code, result_code, result_type, to_py_function=None): - func = self.to_py_function if to_py_function is None else to_py_function - if self.is_string or self.is_pyunicode_ptr: - return '%s = %s(%s)' % ( - result_code, - func, - source_code) - target_is_tuple = result_type.is_builtin_type and result_type.name == 'tuple' - return '%s = %s(%s, %s)' % ( - result_code, - self.to_tuple_function if target_is_tuple else func, - source_code, - self.size) - - def create_from_py_utility_code(self, env): - if self.from_py_function is not None: - return self.from_py_function - if not self.base_type.create_from_py_utility_code(env): - return False - + } + env.use_utility_code(CythonUtilityCode.load( + "carray.to_py", "CConvert.pyx", + outer_module_scope=env.global_scope(), # need access to types declared in module + context=context, compiler_directives=dict(env.global_scope().directives))) + self.to_tuple_function = to_tuple_function + self.to_py_function = to_py_function + return True + + def to_py_call_code(self, source_code, result_code, result_type, to_py_function=None): + func = self.to_py_function if to_py_function is None else to_py_function + if self.is_string or self.is_pyunicode_ptr: + return '%s = %s(%s)' % ( + result_code, + func, + source_code) + target_is_tuple = result_type.is_builtin_type and result_type.name == 'tuple' + return '%s = %s(%s, %s)' % ( + result_code, + self.to_tuple_function if target_is_tuple else func, + source_code, + self.size) + + def create_from_py_utility_code(self, env): + if self.from_py_function is not None: + return self.from_py_function + if not self.base_type.create_from_py_utility_code(env): + return False + from_py_function = "__Pyx_carray_from_py_%s" % self.base_type.specialization_name() - - from .UtilityCode import CythonUtilityCode - context = { - 'cname': from_py_function, + + from .UtilityCode import CythonUtilityCode + context = { + 'cname': from_py_function, 'base_type': self.base_type, - } - env.use_utility_code(CythonUtilityCode.load( - "carray.from_py", "CConvert.pyx", - outer_module_scope=env.global_scope(), # need access to types declared in module - context=context, compiler_directives=dict(env.global_scope().directives))) - self.from_py_function = from_py_function - return True - - def from_py_call_code(self, source_code, result_code, error_pos, code, - from_py_function=None, error_condition=None): + } + env.use_utility_code(CythonUtilityCode.load( + "carray.from_py", "CConvert.pyx", + outer_module_scope=env.global_scope(), # need access to types declared in module + context=context, compiler_directives=dict(env.global_scope().directives))) + self.from_py_function = from_py_function + return True + + def from_py_call_code(self, source_code, result_code, error_pos, code, + from_py_function=None, error_condition=None): assert not error_condition, '%s: %s' % (error_pos, error_condition) - call_code = "%s(%s, %s, %s)" % ( - from_py_function or self.from_py_function, - source_code, result_code, self.size) - return code.error_goto_if_neg(call_code, error_pos) - - + call_code = "%s(%s, %s, %s)" % ( + from_py_function or self.from_py_function, + source_code, result_code, self.size) + return code.error_goto_if_neg(call_code, error_pos) + + class CPtrType(CPointerBaseType): # base_type CType Reference type @@ -2564,7 +2564,7 @@ class CPtrType(CPointerBaseType): return self.base_type.find_cpp_operation_type(operator, operand_type) return None - + class CNullPtrType(CPtrType): is_null_ptr = 1 @@ -2573,7 +2573,7 @@ class CNullPtrType(CPtrType): class CReferenceType(BaseType): is_reference = 1 - is_fake_reference = 0 + is_fake_reference = 0 def __init__(self, base_type): self.ref_base_type = base_type @@ -2596,7 +2596,7 @@ class CReferenceType(BaseType): if base_type == self.ref_base_type: return self else: - return type(self)(base_type) + return type(self)(base_type) def deduce_template_params(self, actual): return self.ref_base_type.deduce_template_params(actual) @@ -2605,22 +2605,22 @@ class CReferenceType(BaseType): return getattr(self.ref_base_type, name) -class CFakeReferenceType(CReferenceType): - - is_fake_reference = 1 - - def __repr__(self): - return "<CFakeReferenceType %s>" % repr(self.ref_base_type) - - def __str__(self): - return "%s [&]" % self.ref_base_type - - def declaration_code(self, entity_code, - for_display = 0, dll_linkage = None, pyrex = 0): - #print "CReferenceType.declaration_code: pointer to", self.base_type ### - return "__Pyx_FakeReference<%s> %s" % (self.ref_base_type.empty_declaration_code(), entity_code) - - +class CFakeReferenceType(CReferenceType): + + is_fake_reference = 1 + + def __repr__(self): + return "<CFakeReferenceType %s>" % repr(self.ref_base_type) + + def __str__(self): + return "%s [&]" % self.ref_base_type + + def declaration_code(self, entity_code, + for_display = 0, dll_linkage = None, pyrex = 0): + #print "CReferenceType.declaration_code: pointer to", self.base_type ### + return "__Pyx_FakeReference<%s> %s" % (self.ref_base_type.empty_declaration_code(), entity_code) + + class CFuncType(CType): # return_type CType # args [CFuncTypeArg] @@ -2668,7 +2668,7 @@ class CFuncType(CType): self.is_strict_signature = is_strict_signature def __repr__(self): - arg_reprs = list(map(repr, self.args)) + arg_reprs = list(map(repr, self.args)) if self.has_varargs: arg_reprs.append("...") if self.exception_value: @@ -2730,8 +2730,8 @@ class CFuncType(CType): # is exempt from compatibility checking (the proper check # is performed elsewhere). for i in range(as_cmethod, nargs): - if not self.args[i].type.same_as(other_type.args[i].type): - return 0 + if not self.args[i].type.same_as(other_type.args[i].type): + return 0 if self.has_varargs != other_type.has_varargs: return 0 if self.optional_arg_count != other_type.optional_arg_count: @@ -2751,25 +2751,25 @@ class CFuncType(CType): if not self._same_exception_value(other_type.exception_value): return 0 elif not self._is_exception_compatible_with(other_type): - return 0 + return 0 + return 1 + + def _same_exception_value(self, other_exc_value): + if self.exception_value == other_exc_value: + return 1 + if self.exception_check != '+': + return 0 + if not self.exception_value or not other_exc_value: + return 0 + if self.exception_value.type != other_exc_value.type: + return 0 + if self.exception_value.entry and other_exc_value.entry: + if self.exception_value.entry.cname != other_exc_value.entry.cname: + return 0 + if self.exception_value.name != other_exc_value.name: + return 0 return 1 - def _same_exception_value(self, other_exc_value): - if self.exception_value == other_exc_value: - return 1 - if self.exception_check != '+': - return 0 - if not self.exception_value or not other_exc_value: - return 0 - if self.exception_value.type != other_exc_value.type: - return 0 - if self.exception_value.entry and other_exc_value.entry: - if self.exception_value.entry.cname != other_exc_value.entry.cname: - return 0 - if self.exception_value.name != other_exc_value.name: - return 0 - return 1 - def compatible_signature_with(self, other_type, as_cmethod = 0): return self.compatible_signature_with_resolved_type(other_type.resolve(), as_cmethod) @@ -2803,7 +2803,7 @@ class CFuncType(CType): if self.nogil != other_type.nogil: return 0 if not self._is_exception_compatible_with(other_type): - return 0 + return 0 self.original_sig = other_type.original_sig or other_type return 1 @@ -2844,11 +2844,11 @@ class CFuncType(CType): return 0 if not self.return_type.subtype_of_resolved_type(other_type.return_type): return 0 - if not self.exception_check and other_type.exception_check: - # a redundant exception check doesn't make functions incompatible, but a missing one does - return 0 - if not self._same_exception_value(other_type.exception_value): - return 0 + if not self.exception_check and other_type.exception_check: + # a redundant exception check doesn't make functions incompatible, but a missing one does + return 0 + if not self._same_exception_value(other_type.exception_value): + return 0 return 1 def same_calling_convention_as(self, other): @@ -2902,9 +2902,9 @@ class CFuncType(CType): trailer = " except %s" % self.exception_value elif self.exception_check == '+': trailer = " except +" - elif self.exception_check and for_display: - # not spelled out by default, unless for human eyes - trailer = " except *" + elif self.exception_check and for_display: + # not spelled out by default, unless for human eyes + trailer = " except *" if self.nogil: trailer += " nogil" if not with_calling_convention: @@ -2929,7 +2929,7 @@ class CFuncType(CType): func_name, arg_code, trailer) def signature_string(self): - s = self.empty_declaration_code() + s = self.empty_declaration_code() return s def signature_cast_string(self): @@ -3029,86 +3029,86 @@ class CFuncType(CType): assert not self.is_fused specialize_entry(entry, cname) - def can_coerce_to_pyobject(self, env): - # duplicating the decisions from create_to_py_utility_code() here avoids writing out unused code - if self.has_varargs or self.optional_arg_count: - return False - if self.to_py_function is not None: - return self.to_py_function - for arg in self.args: - if not arg.type.is_pyobject and not arg.type.can_coerce_to_pyobject(env): - return False - if not self.return_type.is_pyobject and not self.return_type.can_coerce_to_pyobject(env): - return False - return True - - def create_to_py_utility_code(self, env): - # FIXME: it seems we're trying to coerce in more cases than we should - if self.to_py_function is not None: - return self.to_py_function - if not self.can_coerce_to_pyobject(env): - return False - from .UtilityCode import CythonUtilityCode - safe_typename = re.sub('[^a-zA-Z0-9]', '__', self.declaration_code("", pyrex=1)) - to_py_function = "__Pyx_CFunc_%s_to_py" % safe_typename - - for arg in self.args: - if not arg.type.is_pyobject and not arg.type.create_from_py_utility_code(env): - return False - if not self.return_type.is_pyobject and not self.return_type.create_to_py_utility_code(env): - return False - - def declared_type(ctype): - type_displayname = str(ctype.declaration_code("", for_display=True)) - if ctype.is_pyobject: - arg_ctype = type_name = type_displayname - if ctype.is_builtin_type: - arg_ctype = ctype.name - elif not ctype.is_extension_type: - type_name = 'object' - type_displayname = None - else: - type_displayname = repr(type_displayname) - elif ctype is c_bint_type: - type_name = arg_ctype = 'bint' - else: - type_name = arg_ctype = type_displayname - if ctype is c_double_type: - type_displayname = 'float' - else: - type_displayname = repr(type_displayname) - return type_name, arg_ctype, type_displayname - - class Arg(object): - def __init__(self, arg_name, arg_type): - self.name = arg_name - self.type = arg_type - self.type_cname, self.ctype, self.type_displayname = declared_type(arg_type) - - if self.return_type.is_void: - except_clause = 'except *' - elif self.return_type.is_pyobject: - except_clause = '' - elif self.exception_value: - except_clause = ('except? %s' if self.exception_check else 'except %s') % self.exception_value - else: - except_clause = 'except *' - - context = { - 'cname': to_py_function, - 'args': [Arg(arg.name or 'arg%s' % ix, arg.type) for ix, arg in enumerate(self.args)], - 'return_type': Arg('return', self.return_type), - 'except_clause': except_clause, - } - # FIXME: directives come from first defining environment and do not adapt for reuse - env.use_utility_code(CythonUtilityCode.load( - "cfunc.to_py", "CConvert.pyx", - outer_module_scope=env.global_scope(), # need access to types declared in module - context=context, compiler_directives=dict(env.global_scope().directives))) - self.to_py_function = to_py_function - return True - - + def can_coerce_to_pyobject(self, env): + # duplicating the decisions from create_to_py_utility_code() here avoids writing out unused code + if self.has_varargs or self.optional_arg_count: + return False + if self.to_py_function is not None: + return self.to_py_function + for arg in self.args: + if not arg.type.is_pyobject and not arg.type.can_coerce_to_pyobject(env): + return False + if not self.return_type.is_pyobject and not self.return_type.can_coerce_to_pyobject(env): + return False + return True + + def create_to_py_utility_code(self, env): + # FIXME: it seems we're trying to coerce in more cases than we should + if self.to_py_function is not None: + return self.to_py_function + if not self.can_coerce_to_pyobject(env): + return False + from .UtilityCode import CythonUtilityCode + safe_typename = re.sub('[^a-zA-Z0-9]', '__', self.declaration_code("", pyrex=1)) + to_py_function = "__Pyx_CFunc_%s_to_py" % safe_typename + + for arg in self.args: + if not arg.type.is_pyobject and not arg.type.create_from_py_utility_code(env): + return False + if not self.return_type.is_pyobject and not self.return_type.create_to_py_utility_code(env): + return False + + def declared_type(ctype): + type_displayname = str(ctype.declaration_code("", for_display=True)) + if ctype.is_pyobject: + arg_ctype = type_name = type_displayname + if ctype.is_builtin_type: + arg_ctype = ctype.name + elif not ctype.is_extension_type: + type_name = 'object' + type_displayname = None + else: + type_displayname = repr(type_displayname) + elif ctype is c_bint_type: + type_name = arg_ctype = 'bint' + else: + type_name = arg_ctype = type_displayname + if ctype is c_double_type: + type_displayname = 'float' + else: + type_displayname = repr(type_displayname) + return type_name, arg_ctype, type_displayname + + class Arg(object): + def __init__(self, arg_name, arg_type): + self.name = arg_name + self.type = arg_type + self.type_cname, self.ctype, self.type_displayname = declared_type(arg_type) + + if self.return_type.is_void: + except_clause = 'except *' + elif self.return_type.is_pyobject: + except_clause = '' + elif self.exception_value: + except_clause = ('except? %s' if self.exception_check else 'except %s') % self.exception_value + else: + except_clause = 'except *' + + context = { + 'cname': to_py_function, + 'args': [Arg(arg.name or 'arg%s' % ix, arg.type) for ix, arg in enumerate(self.args)], + 'return_type': Arg('return', self.return_type), + 'except_clause': except_clause, + } + # FIXME: directives come from first defining environment and do not adapt for reuse + env.use_utility_code(CythonUtilityCode.load( + "cfunc.to_py", "CConvert.pyx", + outer_module_scope=env.global_scope(), # need access to types declared in module + context=context, compiler_directives=dict(env.global_scope().directives))) + self.to_py_function = to_py_function + return True + + def specialize_entry(entry, cname): """ Specialize an entry of a copied fused function or method @@ -3195,15 +3195,15 @@ def specialization_signature_string(fused_compound_type, fused_to_specific): return fused_type.specialize(fused_to_specific).typeof_name() - + def get_specialized_types(type): """ - Return a list of specialized types in their declared order. + Return a list of specialized types in their declared order. """ assert type.is_fused if isinstance(type, FusedType): - result = list(type.types) + result = list(type.types) for specialized_type in result: specialized_type.specialization_string = specialized_type.typeof_name() else: @@ -3214,7 +3214,7 @@ def get_specialized_types(type): specialization_signature_string(type, f2s)) result.append(specialized_type) - return result + return result class CFuncTypeArg(BaseType): @@ -3258,12 +3258,12 @@ class ToPyStructUtilityCode(object): requires = None - def __init__(self, type, forward_decl, env): + def __init__(self, type, forward_decl, env): self.type = type self.header = "static PyObject* %s(%s)" % (type.to_py_function, type.declaration_code('s')) self.forward_decl = forward_decl - self.env = env + self.env = env def __eq__(self, other): return isinstance(other, ToPyStructUtilityCode) and self.header == other.header @@ -3271,7 +3271,7 @@ class ToPyStructUtilityCode(object): def __hash__(self): return hash(self.header) - def get_tree(self, **kwargs): + def get_tree(self, **kwargs): pass def put_code(self, output): @@ -3285,9 +3285,9 @@ class ToPyStructUtilityCode(object): len(self.type.scope.var_entries)) for member in self.type.scope.var_entries: nameconst_cname = code.get_py_string_const(member.name, identifier=True) - code.putln("%s; if (unlikely(!member)) goto bad;" % ( - member.type.to_py_call_code('s.%s' % member.cname, 'member', member.type))) - code.putln("if (unlikely(PyDict_SetItem(res, %s, member) < 0)) goto bad;" % nameconst_cname) + code.putln("%s; if (unlikely(!member)) goto bad;" % ( + member.type.to_py_call_code('s.%s' % member.cname, 'member', member.type))) + code.putln("if (unlikely(PyDict_SetItem(res, %s, member) < 0)) goto bad;" % nameconst_cname) code.putln("Py_DECREF(member);") code.putln("return res;") code.putln("bad:") @@ -3299,7 +3299,7 @@ class ToPyStructUtilityCode(object): # This is a bit of a hack, we need a forward declaration # due to the way things are ordered in the module... if self.forward_decl: - proto.putln(self.type.empty_declaration_code() + ';') + proto.putln(self.type.empty_declaration_code() + ';') proto.putln(self.header + ";") def inject_tree_and_scope_into(self, module_node): @@ -3327,10 +3327,10 @@ class CStructOrUnionType(CType): self.scope = scope self.typedef_flag = typedef_flag self.is_struct = kind == 'struct' - self.to_py_function = "%s_to_py_%s" % ( - Naming.convert_func_prefix, self.specialization_name()) - self.from_py_function = "%s_from_py_%s" % ( - Naming.convert_func_prefix, self.specialization_name()) + self.to_py_function = "%s_to_py_%s" % ( + Naming.convert_func_prefix, self.specialization_name()) + self.from_py_function = "%s_from_py_%s" % ( + Naming.convert_func_prefix, self.specialization_name()) self.exception_check = True self._convert_to_py_code = None self._convert_from_py_code = None @@ -3344,27 +3344,27 @@ class CStructOrUnionType(CType): return False if self._convert_to_py_code is None: - is_union = not self.is_struct - unsafe_union_types = set() - safe_union_types = set() + is_union = not self.is_struct + unsafe_union_types = set() + safe_union_types = set() for member in self.scope.var_entries: - member_type = member.type + member_type = member.type if not member_type.can_coerce_to_pyobject(env): self.to_py_function = None self._convert_to_py_code = False return False - if is_union: - if member_type.is_ptr or member_type.is_cpp_class: - unsafe_union_types.add(member_type) - else: - safe_union_types.add(member_type) - - if unsafe_union_types and (safe_union_types or len(unsafe_union_types) > 1): - # unsafe mix of safe and unsafe to convert types - self.from_py_function = None - self._convert_from_py_code = False - return False - + if is_union: + if member_type.is_ptr or member_type.is_cpp_class: + unsafe_union_types.add(member_type) + else: + safe_union_types.add(member_type) + + if unsafe_union_types and (safe_union_types or len(unsafe_union_types) > 1): + # unsafe mix of safe and unsafe to convert types + self.from_py_function = None + self._convert_from_py_code = False + return False + return True def create_to_py_utility_code(self, env): @@ -3374,9 +3374,9 @@ class CStructOrUnionType(CType): if self._convert_to_py_code is None: for member in self.scope.var_entries: member.type.create_to_py_utility_code(env) - forward_decl = self.entry.visibility != 'extern' and not self.typedef_flag - self._convert_to_py_code = ToPyStructUtilityCode(self, forward_decl, env) - + forward_decl = self.entry.visibility != 'extern' and not self.typedef_flag + self._convert_to_py_code = ToPyStructUtilityCode(self, forward_decl, env) + env.use_utility_code(self._convert_to_py_code) return True @@ -3412,12 +3412,12 @@ class CStructOrUnionType(CType): var_entries=self.scope.var_entries, funcname=self.from_py_function, ) - from .UtilityCode import CythonUtilityCode - self._convert_from_py_code = CythonUtilityCode.load( - "FromPyStructUtility" if self.is_struct else "FromPyUnionUtility", - "CConvert.pyx", - outer_module_scope=env.global_scope(), # need access to types declared in module - context=context) + from .UtilityCode import CythonUtilityCode + self._convert_from_py_code = CythonUtilityCode.load( + "FromPyStructUtility" if self.is_struct else "FromPyUnionUtility", + "CConvert.pyx", + outer_module_scope=env.global_scope(), # need access to types declared in module + context=context) env.use_utility_code(self._convert_from_py_code) return True @@ -3469,8 +3469,8 @@ class CStructOrUnionType(CType): if len(fields) != 2: return False a, b = fields return (a.type.is_float and b.type.is_float and - a.type.empty_declaration_code() == - b.type.empty_declaration_code()) + a.type.empty_declaration_code() == + b.type.empty_declaration_code()) def struct_nesting_depth(self): child_depths = [x.type.struct_nesting_depth() @@ -3484,22 +3484,22 @@ class CStructOrUnionType(CType): cpp_string_conversions = ("std::string", "TString", "TStringBuf") -builtin_cpp_conversions = { - # type element template params - "std::pair": 2, - "std::vector": 1, - "std::list": 1, - "std::set": 1, - "std::unordered_set": 1, - "std::map": 2, - "std::unordered_map": 2, - "std::complex": 1, - # arcadia_cpp_conversions - "TMaybe": 1, +builtin_cpp_conversions = { + # type element template params + "std::pair": 2, + "std::vector": 1, + "std::list": 1, + "std::set": 1, + "std::unordered_set": 1, + "std::map": 2, + "std::unordered_map": 2, + "std::complex": 1, + # arcadia_cpp_conversions + "TMaybe": 1, "TVector": 1, "THashMap": 2, "TMap": 2, -} +} class CppClassType(CType): # name string @@ -3519,7 +3519,7 @@ class CppClassType(CType): subtypes = ['templates'] - def __init__(self, name, scope, cname, base_classes, templates=None, template_type=None): + def __init__(self, name, scope, cname, base_classes, templates=None, template_type=None): self.name = name self.cname = cname self.scope = scope @@ -3527,11 +3527,11 @@ class CppClassType(CType): self.operators = [] self.templates = templates self.template_type = template_type - self.num_optional_templates = sum(is_optional_template_param(T) for T in templates or ()) - if templates and False: # https://github.com/cython/cython/issues/1868 - self.specializations = {tuple(zip(templates, templates)): self} - else: - self.specializations = {} + self.num_optional_templates = sum(is_optional_template_param(T) for T in templates or ()) + if templates and False: # https://github.com/cython/cython/issues/1868 + self.specializations = {tuple(zip(templates, templates)): self} + else: + self.specializations = {} self.is_cpp_string = cname in cpp_string_conversions def use_conversion_utility(self, from_or_to): @@ -3559,13 +3559,13 @@ class CppClassType(CType): def create_from_py_utility_code(self, env): if self.from_py_function is not None: return True - if self.cname in builtin_cpp_conversions or self.cname in cpp_string_conversions: + if self.cname in builtin_cpp_conversions or self.cname in cpp_string_conversions: X = "XYZABC" tags = [] context = {} for ix, T in enumerate(self.templates or []): - if ix >= builtin_cpp_conversions[self.cname]: - break + if ix >= builtin_cpp_conversions[self.cname]: + break if T.is_pyobject or not T.create_from_py_utility_code(env): return False tags.append(T.specialization_name()) @@ -3573,19 +3573,19 @@ class CppClassType(CType): if self.cname in cpp_string_conversions: cls = 'string' - tags = type_identifier(self), + tags = type_identifier(self), elif self.cname.startswith('std::'): cls = self.cname[5:] else: cls = 'arcadia_' + self.cname - cname = '__pyx_convert_%s_from_py_%s' % (cls, '__and_'.join(tags)) + cname = '__pyx_convert_%s_from_py_%s' % (cls, '__and_'.join(tags)) context.update({ 'cname': cname, 'maybe_unordered': self.maybe_unordered(), 'type': self.cname, }) from .UtilityCode import CythonUtilityCode - env.use_utility_code(CythonUtilityCode.load( + env.use_utility_code(CythonUtilityCode.load( cls.replace('unordered_', '') + ".from_py", "CppConvert.pyx", context=context, compiler_directives=env.directives)) self.from_py_function = cname @@ -3603,13 +3603,13 @@ class CppClassType(CType): def create_to_py_utility_code(self, env): if self.to_py_function is not None: return True - if self.cname in builtin_cpp_conversions or self.cname in cpp_string_conversions: + if self.cname in builtin_cpp_conversions or self.cname in cpp_string_conversions: X = "XYZABC" tags = [] context = {} for ix, T in enumerate(self.templates or []): - if ix >= builtin_cpp_conversions[self.cname]: - break + if ix >= builtin_cpp_conversions[self.cname]: + break if not T.create_to_py_utility_code(env): return False tags.append(T.specialization_name()) @@ -3617,60 +3617,60 @@ class CppClassType(CType): if self.cname in cpp_string_conversions: cls = 'string' - prefix = 'PyObject_' # gets specialised by explicit type casts in CoerceToPyTypeNode - tags = type_identifier(self), + prefix = 'PyObject_' # gets specialised by explicit type casts in CoerceToPyTypeNode + tags = type_identifier(self), elif self.cname.startswith('std::'): cls = self.cname[5:] - prefix = '' + prefix = '' else: cls = 'arcadia_' + self.cname prefix = '' - cname = "__pyx_convert_%s%s_to_py_%s" % (prefix, cls, "____".join(tags)) + cname = "__pyx_convert_%s%s_to_py_%s" % (prefix, cls, "____".join(tags)) context.update({ 'cname': cname, 'maybe_unordered': self.maybe_unordered(), 'type': self.cname, }) from .UtilityCode import CythonUtilityCode - env.use_utility_code(CythonUtilityCode.load( + env.use_utility_code(CythonUtilityCode.load( cls.replace('unordered_', '') + ".to_py", "CppConvert.pyx", context=context, compiler_directives=env.directives)) self.to_py_function = cname return True - def is_template_type(self): - return self.templates is not None and self.template_type is None - - def get_fused_types(self, result=None, seen=None): - if result is None: - result = [] - seen = set() - if self.namespace: - self.namespace.get_fused_types(result, seen) - if self.templates: - for T in self.templates: - T.get_fused_types(result, seen) - return result - - def specialize_here(self, pos, template_values=None): - if not self.is_template_type(): + def is_template_type(self): + return self.templates is not None and self.template_type is None + + def get_fused_types(self, result=None, seen=None): + if result is None: + result = [] + seen = set() + if self.namespace: + self.namespace.get_fused_types(result, seen) + if self.templates: + for T in self.templates: + T.get_fused_types(result, seen) + return result + + def specialize_here(self, pos, template_values=None): + if not self.is_template_type(): error(pos, "'%s' type is not a template" % self) return error_type - if len(self.templates) - self.num_optional_templates <= len(template_values) < len(self.templates): - num_defaults = len(self.templates) - len(template_values) - partial_specialization = self.declaration_code('', template_params=template_values) - # Most of the time we don't need to declare anything typed to these - # default template arguments, but when we do there's no way in C++ - # to reference this directly. However, it is common convention to - # provide a typedef in the template class that resolves to each - # template type. For now, allow the user to specify this name as - # the template parameter. - # TODO: Allow typedefs in cpp classes and search for it in this - # classes scope as a concrete name we could use. - template_values = template_values + [ - TemplatePlaceholderType( - "%s::%s" % (partial_specialization, param.name), True) - for param in self.templates[-num_defaults:]] + if len(self.templates) - self.num_optional_templates <= len(template_values) < len(self.templates): + num_defaults = len(self.templates) - len(template_values) + partial_specialization = self.declaration_code('', template_params=template_values) + # Most of the time we don't need to declare anything typed to these + # default template arguments, but when we do there's no way in C++ + # to reference this directly. However, it is common convention to + # provide a typedef in the template class that resolves to each + # template type. For now, allow the user to specify this name as + # the template parameter. + # TODO: Allow typedefs in cpp classes and search for it in this + # classes scope as a concrete name we could use. + template_values = template_values + [ + TemplatePlaceholderType( + "%s::%s" % (partial_specialization, param.name), True) + for param in self.templates[-num_defaults:]] if len(self.templates) != len(template_values): error(pos, "%s templated type receives %d arguments, got %d" % (self.name, len(self.templates), len(template_values))) @@ -3701,20 +3701,20 @@ class CppClassType(CType): specialized.base_classes = [b.specialize(values) for b in self.base_classes] if self.namespace is not None: specialized.namespace = self.namespace.specialize(values) - specialized.scope = self.scope.specialize(values, specialized) - if self.cname == 'std::vector': - # vector<bool> is special cased in the C++ standard, and its - # accessors do not necessarily return references to the underlying - # elements (which may be bit-packed). - # http://www.cplusplus.com/reference/vector/vector-bool/ - # Here we pretend that the various methods return bool values - # (as the actual returned values are coercable to such, and - # we don't support call expressions as lvalues). - T = values.get(self.templates[0], None) - if T and not T.is_fused and T.empty_declaration_code() == 'bool': - for bit_ref_returner in ('at', 'back', 'front'): - if bit_ref_returner in specialized.scope.entries: - specialized.scope.entries[bit_ref_returner].type.return_type = T + specialized.scope = self.scope.specialize(values, specialized) + if self.cname == 'std::vector': + # vector<bool> is special cased in the C++ standard, and its + # accessors do not necessarily return references to the underlying + # elements (which may be bit-packed). + # http://www.cplusplus.com/reference/vector/vector-bool/ + # Here we pretend that the various methods return bool values + # (as the actual returned values are coercable to such, and + # we don't support call expressions as lvalues). + T = values.get(self.templates[0], None) + if T and not T.is_fused and T.empty_declaration_code() == 'bool': + for bit_ref_returner in ('at', 'back', 'front'): + if bit_ref_returner in specialized.scope.entries: + specialized.scope.entries[bit_ref_returner].type.return_type = T return specialized def deduce_template_params(self, actual): @@ -3724,16 +3724,16 @@ class CppClassType(CType): actual = actual.ref_base_type if self == actual: return {} - elif actual.is_cpp_class: + elif actual.is_cpp_class: self_template_type = self while getattr(self_template_type, 'template_type', None): self_template_type = self_template_type.template_type - def all_bases(cls): - yield cls - for parent in cls.base_classes: - for base in all_bases(parent): - yield base - for actual_base in all_bases(actual): + def all_bases(cls): + yield cls + for parent in cls.base_classes: + for base in all_bases(parent): + yield base + for actual_base in all_bases(actual): template_type = actual_base while getattr(template_type, 'template_type', None): template_type = template_type.template_type @@ -3746,17 +3746,17 @@ class CppClassType(CType): in zip(self.templates, actual_base.templates)], {}) else: - return {} + return {} def declaration_code(self, entity_code, - for_display = 0, dll_linkage = None, pyrex = 0, - template_params = None): - if template_params is None: - template_params = self.templates + for_display = 0, dll_linkage = None, pyrex = 0, + template_params = None): + if template_params is None: + template_params = self.templates if self.templates: template_strings = [param.declaration_code('', for_display, None, pyrex) - for param in template_params - if not is_optional_template_param(param) and not param.is_fused] + for param in template_params + if not is_optional_template_param(param) and not param.is_fused] if for_display: brackets = "[%s]" else: @@ -3769,7 +3769,7 @@ class CppClassType(CType): else: base_code = "%s%s" % (self.cname, templates) if self.namespace is not None: - base_code = "%s::%s" % (self.namespace.empty_declaration_code(), base_code) + base_code = "%s::%s" % (self.namespace.empty_declaration_code(), base_code) base_code = public_decl(base_code, dll_linkage) return self.base_declaration_code(base_code, entity_code) @@ -3801,7 +3801,7 @@ class CppClassType(CType): if self.templates == other_type.templates: return 1 for t1, t2 in zip(self.templates, other_type.templates): - if is_optional_template_param(t1) and is_optional_template_param(t2): + if is_optional_template_param(t1) and is_optional_template_param(t2): break if not t1.same_as_resolved_type(t2): return 0 @@ -3858,9 +3858,9 @@ class CppClassType(CType): class TemplatePlaceholderType(CType): - def __init__(self, name, optional=False): + def __init__(self, name, optional=False): self.name = name - self.optional = optional + self.optional = optional def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0): @@ -3899,27 +3899,27 @@ class TemplatePlaceholderType(CType): else: return False -def is_optional_template_param(type): - return isinstance(type, TemplatePlaceholderType) and type.optional - - +def is_optional_template_param(type): + return isinstance(type, TemplatePlaceholderType) and type.optional + + class CEnumType(CIntLike, CType): # name string # cname string or None # typedef_flag boolean - # values [string], populated during declaration analysis + # values [string], populated during declaration analysis is_enum = 1 signed = 1 rank = -1 # Ranks below any integer type - def __init__(self, name, cname, typedef_flag, namespace=None): + def __init__(self, name, cname, typedef_flag, namespace=None): self.name = name self.cname = cname self.values = [] self.typedef_flag = typedef_flag - self.namespace = namespace - self.default_value = "(%s) 0" % self.empty_declaration_code() + self.namespace = namespace + self.default_value = "(%s) 0" % self.empty_declaration_code() def __str__(self): return self.name @@ -3933,127 +3933,127 @@ class CEnumType(CIntLike, CType): if pyrex or for_display: base_code = self.name else: - if self.namespace: - base_code = "%s::%s" % ( - self.namespace.empty_declaration_code(), self.cname) - elif self.typedef_flag: + if self.namespace: + base_code = "%s::%s" % ( + self.namespace.empty_declaration_code(), self.cname) + elif self.typedef_flag: base_code = self.cname else: base_code = "enum %s" % self.cname base_code = public_decl(base_code, dll_linkage) return self.base_declaration_code(base_code, entity_code) - def specialize(self, values): - if self.namespace: - namespace = self.namespace.specialize(values) - if namespace != self.namespace: - return CEnumType( - self.name, self.cname, self.typedef_flag, namespace) - return self - - def create_type_wrapper(self, env): - from .UtilityCode import CythonUtilityCode - env.use_utility_code(CythonUtilityCode.load( - "EnumType", "CpdefEnums.pyx", - context={"name": self.name, - "items": tuple(self.values)}, - outer_module_scope=env.global_scope())) - - -class CTupleType(CType): - # components [PyrexType] - - is_ctuple = True - - def __init__(self, cname, components): - self.cname = cname - self.components = components - self.size = len(components) - self.to_py_function = "%s_to_py_%s" % (Naming.convert_func_prefix, self.cname) - self.from_py_function = "%s_from_py_%s" % (Naming.convert_func_prefix, self.cname) - self.exception_check = True - self._convert_to_py_code = None - self._convert_from_py_code = None - - def __str__(self): - return "(%s)" % ", ".join(str(c) for c in self.components) - - def declaration_code(self, entity_code, - for_display = 0, dll_linkage = None, pyrex = 0): - if pyrex or for_display: - return str(self) - else: - return self.base_declaration_code(self.cname, entity_code) - - def can_coerce_to_pyobject(self, env): - for component in self.components: - if not component.can_coerce_to_pyobject(env): - return False - return True - + def specialize(self, values): + if self.namespace: + namespace = self.namespace.specialize(values) + if namespace != self.namespace: + return CEnumType( + self.name, self.cname, self.typedef_flag, namespace) + return self + + def create_type_wrapper(self, env): + from .UtilityCode import CythonUtilityCode + env.use_utility_code(CythonUtilityCode.load( + "EnumType", "CpdefEnums.pyx", + context={"name": self.name, + "items": tuple(self.values)}, + outer_module_scope=env.global_scope())) + + +class CTupleType(CType): + # components [PyrexType] + + is_ctuple = True + + def __init__(self, cname, components): + self.cname = cname + self.components = components + self.size = len(components) + self.to_py_function = "%s_to_py_%s" % (Naming.convert_func_prefix, self.cname) + self.from_py_function = "%s_from_py_%s" % (Naming.convert_func_prefix, self.cname) + self.exception_check = True + self._convert_to_py_code = None + self._convert_from_py_code = None + + def __str__(self): + return "(%s)" % ", ".join(str(c) for c in self.components) + + def declaration_code(self, entity_code, + for_display = 0, dll_linkage = None, pyrex = 0): + if pyrex or for_display: + return str(self) + else: + return self.base_declaration_code(self.cname, entity_code) + + def can_coerce_to_pyobject(self, env): + for component in self.components: + if not component.can_coerce_to_pyobject(env): + return False + return True + def can_coerce_from_pyobject(self, env): for component in self.components: if not component.can_coerce_from_pyobject(env): return False return True - def create_to_py_utility_code(self, env): - if self._convert_to_py_code is False: - return None # tri-state-ish - - if self._convert_to_py_code is None: - for component in self.components: - if not component.create_to_py_utility_code(env): - self.to_py_function = None - self._convert_to_py_code = False - return False - - context = dict( - struct_type_decl=self.empty_declaration_code(), - components=self.components, - funcname=self.to_py_function, - size=len(self.components) - ) - self._convert_to_py_code = TempitaUtilityCode.load( - "ToPyCTupleUtility", "TypeConversion.c", context=context) - - env.use_utility_code(self._convert_to_py_code) - return True - - def create_from_py_utility_code(self, env): - if self._convert_from_py_code is False: - return None # tri-state-ish - - if self._convert_from_py_code is None: - for component in self.components: - if not component.create_from_py_utility_code(env): - self.from_py_function = None - self._convert_from_py_code = False - return False - - context = dict( - struct_type_decl=self.empty_declaration_code(), - components=self.components, - funcname=self.from_py_function, - size=len(self.components) - ) - self._convert_from_py_code = TempitaUtilityCode.load( - "FromPyCTupleUtility", "TypeConversion.c", context=context) - - env.use_utility_code(self._convert_from_py_code) - return True - + def create_to_py_utility_code(self, env): + if self._convert_to_py_code is False: + return None # tri-state-ish + + if self._convert_to_py_code is None: + for component in self.components: + if not component.create_to_py_utility_code(env): + self.to_py_function = None + self._convert_to_py_code = False + return False + + context = dict( + struct_type_decl=self.empty_declaration_code(), + components=self.components, + funcname=self.to_py_function, + size=len(self.components) + ) + self._convert_to_py_code = TempitaUtilityCode.load( + "ToPyCTupleUtility", "TypeConversion.c", context=context) + + env.use_utility_code(self._convert_to_py_code) + return True + + def create_from_py_utility_code(self, env): + if self._convert_from_py_code is False: + return None # tri-state-ish + + if self._convert_from_py_code is None: + for component in self.components: + if not component.create_from_py_utility_code(env): + self.from_py_function = None + self._convert_from_py_code = False + return False + + context = dict( + struct_type_decl=self.empty_declaration_code(), + components=self.components, + funcname=self.from_py_function, + size=len(self.components) + ) + self._convert_from_py_code = TempitaUtilityCode.load( + "FromPyCTupleUtility", "TypeConversion.c", context=context) + + env.use_utility_code(self._convert_from_py_code) + return True + def cast_code(self, expr_code): return expr_code - - -def c_tuple_type(components): - components = tuple(components) - cname = Naming.ctuple_type_prefix + type_list_identifier(components) - tuple_type = CTupleType(cname, components) - return tuple_type - - + + +def c_tuple_type(components): + components = tuple(components) + cname = Naming.ctuple_type_prefix + type_list_identifier(components) + tuple_type = CTupleType(cname, components) + return tuple_type + + class UnspecifiedType(PyrexType): # Used as a placeholder until the type can be determined. @@ -4159,13 +4159,13 @@ c_null_ptr_type = CNullPtrType(c_void_type) c_void_ptr_type = CPtrType(c_void_type) c_void_ptr_ptr_type = CPtrType(c_void_ptr_type) c_char_ptr_type = CPtrType(c_char_type) -c_const_char_ptr_type = CPtrType(CConstType(c_char_type)) +c_const_char_ptr_type = CPtrType(CConstType(c_char_type)) c_uchar_ptr_type = CPtrType(c_uchar_type) -c_const_uchar_ptr_type = CPtrType(CConstType(c_uchar_type)) +c_const_uchar_ptr_type = CPtrType(CConstType(c_uchar_type)) c_char_ptr_ptr_type = CPtrType(c_char_ptr_type) c_int_ptr_type = CPtrType(c_int_type) c_py_unicode_ptr_type = CPtrType(c_py_unicode_type) -c_const_py_unicode_ptr_type = CPtrType(CConstType(c_py_unicode_type)) +c_const_py_unicode_ptr_type = CPtrType(CConstType(c_py_unicode_type)) c_py_ssize_t_ptr_type = CPtrType(c_py_ssize_t_type) c_ssize_t_ptr_type = CPtrType(c_ssize_t_type) c_size_t_ptr_type = CPtrType(c_size_t_type) @@ -4270,7 +4270,7 @@ def is_promotion(src_type, dst_type): return src_type.is_float and src_type.rank <= dst_type.rank return False -def best_match(arg_types, functions, pos=None, env=None, args=None): +def best_match(arg_types, functions, pos=None, env=None, args=None): """ Given a list args of arguments and a list of functions, choose one to call which seems to be the "best" fit for this list of arguments. @@ -4293,7 +4293,7 @@ def best_match(arg_types, functions, pos=None, env=None, args=None): is not None, we also generate an error. """ # TODO: args should be a list of types, not a list of Nodes. - actual_nargs = len(arg_types) + actual_nargs = len(arg_types) candidates = [] errors = [] @@ -4338,7 +4338,7 @@ def best_match(arg_types, functions, pos=None, env=None, args=None): from .Symtab import Entry specialization = Entry( name = func.name + "[%s]" % ",".join([str(t) for t in type_list]), - cname = func.cname + "<%s>" % ",".join([t.empty_declaration_code() for t in type_list]), + cname = func.cname + "<%s>" % ",".join([t.empty_declaration_code() for t in type_list]), type = func_type.specialize(deductions), pos = func.pos) candidates.append((specialization, specialization.type)) @@ -4363,13 +4363,13 @@ def best_match(arg_types, functions, pos=None, env=None, args=None): for index, (func, func_type) in enumerate(candidates): score = [0,0,0,0,0,0,0] - for i in range(min(actual_nargs, len(func_type.args))): - src_type = arg_types[i] + for i in range(min(actual_nargs, len(func_type.args))): + src_type = arg_types[i] dst_type = func_type.args[i].type assignable = dst_type.assignable_from(src_type) - # Now take care of unprefixed string literals. So when you call a cdef + # Now take care of unprefixed string literals. So when you call a cdef # function that takes a char *, the coercion will mean that the # type will simply become bytes. We need to do this coercion # manually for overloaded and fused functions @@ -4387,13 +4387,13 @@ def best_match(arg_types, functions, pos=None, env=None, args=None): assignable = dst_type.assignable_from(c_src_type) if assignable: src_type = c_src_type - needed_coercions[func] = (i, dst_type) + needed_coercions[func] = (i, dst_type) if assignable: if src_type == dst_type or dst_type.same_as(src_type): - pass # score 0 + pass # score 0 elif func_type.is_strict_signature: - break # exact match requested but not found + break # exact match requested but not found elif is_promotion(src_type, dst_type): score[2] += 1 elif ((src_type.is_int and dst_type.is_int) or @@ -4412,11 +4412,11 @@ def best_match(arg_types, functions, pos=None, env=None, args=None): else: score[0] += 1 else: - error_mesg = "Invalid conversion from '%s' to '%s'" % (src_type, dst_type) + error_mesg = "Invalid conversion from '%s' to '%s'" % (src_type, dst_type) bad_types.append((func, error_mesg)) break else: - possibilities.append((score, index, func)) # so we can sort it + possibilities.append((score, index, func)) # so we can sort it if possibilities: possibilities.sort() @@ -4448,7 +4448,7 @@ def merge_template_deductions(a, b): if a is None or b is None: return None all = a - for param, value in b.items(): + for param, value in b.items(): if param in all: if a[param] != b[param]: return None @@ -4458,12 +4458,12 @@ def merge_template_deductions(a, b): def widest_numeric_type(type1, type2): - """Given two numeric types, return the narrowest type encompassing both of them. - """ - if type1.is_reference: - type1 = type1.ref_base_type - if type2.is_reference: - type2 = type2.ref_base_type + """Given two numeric types, return the narrowest type encompassing both of them. + """ + if type1.is_reference: + type1 = type1.ref_base_type + if type2.is_reference: + type2 = type2.ref_base_type if type1.is_const: type1 = type1.const_base_type if type2.is_const: @@ -4487,10 +4487,10 @@ def widest_numeric_type(type1, type2): widest_type = type1 elif type1.signed < type2.signed: widest_type = type1 - elif type1.signed > type2.signed: - widest_type = type2 - elif type1.is_typedef > type2.is_typedef: - widest_type = type1 + elif type1.signed > type2.signed: + widest_type = type2 + elif type1.is_typedef > type2.is_typedef: + widest_type = type1 else: widest_type = type2 return widest_type @@ -4508,11 +4508,11 @@ def independent_spanning_type(type1, type2): # whereas "x = True or 2" must evaluate to a type that can hold # both a boolean value and an integer, so this function works # better. - if type1.is_reference ^ type2.is_reference: - if type1.is_reference: - type1 = type1.ref_base_type - else: - type2 = type2.ref_base_type + if type1.is_reference ^ type2.is_reference: + if type1.is_reference: + type1 = type1.ref_base_type + else: + type2 = type2.ref_base_type if type1 == type2: return type1 elif (type1 is c_bint_type or type2 is c_bint_type) and (type1.is_numeric and type2.is_numeric): @@ -4565,10 +4565,10 @@ def _spanning_type(type1, type2): return py_object_type return type2 elif type1.is_ptr and type2.is_ptr: - if type1.base_type.is_cpp_class and type2.base_type.is_cpp_class: - common_base = widest_cpp_type(type1.base_type, type2.base_type) - if common_base: - return CPtrType(common_base) + if type1.base_type.is_cpp_class and type2.base_type.is_cpp_class: + common_base = widest_cpp_type(type1.base_type, type2.base_type) + if common_base: + return CPtrType(common_base) # incompatible pointers, void* will do as a result return c_void_ptr_type else: @@ -4586,24 +4586,24 @@ def widest_extension_type(type1, type2): if type1 is None or type2 is None: return py_object_type -def widest_cpp_type(type1, type2): - @cached_function - def bases(type): - all = set() - for base in type.base_classes: - all.add(base) - all.update(bases(base)) - return all - common_bases = bases(type1).intersection(bases(type2)) - common_bases_bases = reduce(set.union, [bases(b) for b in common_bases], set()) - candidates = [b for b in common_bases if b not in common_bases_bases] - if len(candidates) == 1: - return candidates[0] - else: - # Fall back to void* for now. - return None - - +def widest_cpp_type(type1, type2): + @cached_function + def bases(type): + all = set() + for base in type.base_classes: + all.add(base) + all.update(bases(base)) + return all + common_bases = bases(type1).intersection(bases(type2)) + common_bases_bases = reduce(set.union, [bases(b) for b in common_bases], set()) + candidates = [b for b in common_bases if b not in common_bases_bases] + if len(candidates) == 1: + return candidates[0] + else: + # Fall back to void* for now. + return None + + def simple_c_type(signed, longness, name): # Find type descriptor for simple type given name and modifiers. # Returns None if arguments don't make sense. @@ -4668,8 +4668,8 @@ def c_ptr_type(base_type): # Construct a C pointer type. if base_type is error_type: return error_type - elif base_type.is_reference: - return CPtrType(base_type.ref_base_type) + elif base_type.is_reference: + return CPtrType(base_type.ref_base_type) else: return CPtrType(base_type) @@ -4707,38 +4707,38 @@ def typecast(to_type, from_type, expr_code): else: #print "typecast: to", to_type, "from", from_type ### return to_type.cast_code(expr_code) - -def type_list_identifier(types): - return cap_length('__and_'.join(type_identifier(type) for type in types)) - -_type_identifier_cache = {} -def type_identifier(type): - decl = type.empty_declaration_code() - safe = _type_identifier_cache.get(decl) - if safe is None: - safe = decl - safe = re.sub(' +', ' ', safe) - safe = re.sub(' ([^a-zA-Z0-9_])', r'\1', safe) - safe = re.sub('([^a-zA-Z0-9_]) ', r'\1', safe) - safe = (safe.replace('__', '__dunder') - .replace('const ', '__const_') - .replace(' ', '__space_') - .replace('*', '__ptr') - .replace('&', '__ref') - .replace('[', '__lArr') - .replace(']', '__rArr') - .replace('<', '__lAng') - .replace('>', '__rAng') - .replace('(', '__lParen') - .replace(')', '__rParen') - .replace(',', '__comma_') - .replace('::', '__in_')) - safe = cap_length(re.sub('[^a-zA-Z0-9_]', lambda x: '__%X' % ord(x.group(0)), safe)) - _type_identifier_cache[decl] = safe - return safe - -def cap_length(s, max_prefix=63, max_len=1024): - if len(s) <= max_prefix: - return s + +def type_list_identifier(types): + return cap_length('__and_'.join(type_identifier(type) for type in types)) + +_type_identifier_cache = {} +def type_identifier(type): + decl = type.empty_declaration_code() + safe = _type_identifier_cache.get(decl) + if safe is None: + safe = decl + safe = re.sub(' +', ' ', safe) + safe = re.sub(' ([^a-zA-Z0-9_])', r'\1', safe) + safe = re.sub('([^a-zA-Z0-9_]) ', r'\1', safe) + safe = (safe.replace('__', '__dunder') + .replace('const ', '__const_') + .replace(' ', '__space_') + .replace('*', '__ptr') + .replace('&', '__ref') + .replace('[', '__lArr') + .replace(']', '__rArr') + .replace('<', '__lAng') + .replace('>', '__rAng') + .replace('(', '__lParen') + .replace(')', '__rParen') + .replace(',', '__comma_') + .replace('::', '__in_')) + safe = cap_length(re.sub('[^a-zA-Z0-9_]', lambda x: '__%X' % ord(x.group(0)), safe)) + _type_identifier_cache[decl] = safe + return safe + +def cap_length(s, max_prefix=63, max_len=1024): + if len(s) <= max_prefix: + return s hash_prefix = hashlib.sha256(s.encode('ascii')).hexdigest()[:6] return '%s__%s__etc' % (hash_prefix, s[:max_len-17]) diff --git a/contrib/tools/cython/Cython/Compiler/Pythran.py b/contrib/tools/cython/Cython/Compiler/Pythran.py index 8828c90c80..c02704a918 100644 --- a/contrib/tools/cython/Cython/Compiler/Pythran.py +++ b/contrib/tools/cython/Cython/Compiler/Pythran.py @@ -6,28 +6,28 @@ from .PyrexTypes import CType, CTypedefType, CStructOrUnionType import cython -try: - import pythran - pythran_is_pre_0_9 = tuple(map(int, pythran.__version__.split('.')[0:2])) < (0, 9) +try: + import pythran + pythran_is_pre_0_9 = tuple(map(int, pythran.__version__.split('.')[0:2])) < (0, 9) pythran_is_pre_0_9_6 = tuple(map(int, pythran.__version__.split('.')[0:3])) < (0, 9, 6) -except ImportError: - pythran = None - pythran_is_pre_0_9 = True +except ImportError: + pythran = None + pythran_is_pre_0_9 = True pythran_is_pre_0_9_6 = True if pythran_is_pre_0_9_6: pythran_builtins = '__builtin__' else: pythran_builtins = 'builtins' - + # Pythran/Numpy specific operations def has_np_pythran(env): - if env is None: - return False - directives = getattr(env, 'directives', None) - return (directives and directives.get('np_pythran', False)) + if env is None: + return False + directives = getattr(env, 'directives', None) + return (directives and directives.get('np_pythran', False)) @cython.ccall def is_pythran_supported_dtype(type_): @@ -47,10 +47,10 @@ def pythran_type(Ty, ptype="ndarray"): ctype = dtype.typedef_cname else: raise ValueError("unsupported type %s!" % dtype) - if pythran_is_pre_0_9: - return "pythonic::types::%s<%s,%d>" % (ptype,ctype, ndim) - else: - return "pythonic::types::%s<%s,pythonic::types::pshape<%s>>" % (ptype,ctype, ",".join(("long",)*ndim)) + if pythran_is_pre_0_9: + return "pythonic::types::%s<%s,%d>" % (ptype,ctype, ndim) + else: + return "pythonic::types::%s<%s,pythonic::types::pshape<%s>>" % (ptype,ctype, ",".join(("long",)*ndim)) if Ty.is_pythran_expr: return Ty.pythran_type #if Ty.is_none: @@ -66,12 +66,12 @@ def type_remove_ref(ty): def pythran_binop_type(op, tA, tB): - if op == '**': - return 'decltype(pythonic::numpy::functor::power{}(std::declval<%s>(), std::declval<%s>()))' % ( - pythran_type(tA), pythran_type(tB)) - else: - return "decltype(std::declval<%s>() %s std::declval<%s>())" % ( - pythran_type(tA), op, pythran_type(tB)) + if op == '**': + return 'decltype(pythonic::numpy::functor::power{}(std::declval<%s>(), std::declval<%s>()))' % ( + pythran_type(tA), pythran_type(tB)) + else: + return "decltype(std::declval<%s>() %s std::declval<%s>())" % ( + pythran_type(tA), op, pythran_type(tB)) def pythran_unaryop_type(op, type_): @@ -88,7 +88,7 @@ def _index_access(index_code, indices): def _index_type_code(index_with_type): idx, index_type = index_with_type if idx.is_slice: - n = 2 + int(not idx.step.is_none) + n = 2 + int(not idx.step.is_none) return "pythonic::%s::functor::slice{}(%s)" % ( pythran_builtins, ",".join(["0"]*n)) @@ -126,32 +126,32 @@ def pythran_indexing_type(type_, indices): def pythran_indexing_code(indices): return _index_access(_index_code, indices) -def np_func_to_list(func): - if not func.is_numpy_attribute: - return [] - return np_func_to_list(func.obj) + [func.attribute] - -if pythran is None: - def pythran_is_numpy_func_supported(name): - return False -else: - def pythran_is_numpy_func_supported(func): - CurF = pythran.tables.MODULES['numpy'] - FL = np_func_to_list(func) - for F in FL: - CurF = CurF.get(F, None) - if CurF is None: - return False - return True - -def pythran_functor(func): - func = np_func_to_list(func) - submodules = "::".join(func[:-1] + ["functor"]) - return "pythonic::numpy::%s::%s" % (submodules, func[-1]) - +def np_func_to_list(func): + if not func.is_numpy_attribute: + return [] + return np_func_to_list(func.obj) + [func.attribute] + +if pythran is None: + def pythran_is_numpy_func_supported(name): + return False +else: + def pythran_is_numpy_func_supported(func): + CurF = pythran.tables.MODULES['numpy'] + FL = np_func_to_list(func) + for F in FL: + CurF = CurF.get(F, None) + if CurF is None: + return False + return True + +def pythran_functor(func): + func = np_func_to_list(func) + submodules = "::".join(func[:-1] + ["functor"]) + return "pythonic::numpy::%s::%s" % (submodules, func[-1]) + def pythran_func_type(func, args): args = ",".join(("std::declval<%s>()" % pythran_type(a.type) for a in args)) - return "decltype(%s{}(%s))" % (pythran_functor(func), args) + return "decltype(%s{}(%s))" % (pythran_functor(func), args) @cython.ccall @@ -205,9 +205,9 @@ def is_pythran_buffer(type_): return (type_.is_numpy_buffer and is_pythran_supported_dtype(type_.dtype) and type_.mode in ("c", "strided") and not type_.cast) -def pythran_get_func_include_file(func): - func = np_func_to_list(func) - return "pythonic/numpy/%s.hpp" % "/".join(func) +def pythran_get_func_include_file(func): + func = np_func_to_list(func) + return "pythonic/numpy/%s.hpp" % "/".join(func) def include_pythran_generic(env): # Generic files @@ -215,7 +215,7 @@ def include_pythran_generic(env): env.add_include_file("pythonic/python/core.hpp") env.add_include_file("pythonic/types/bool.hpp") env.add_include_file("pythonic/types/ndarray.hpp") - env.add_include_file("pythonic/numpy/power.hpp") + env.add_include_file("pythonic/numpy/power.hpp") env.add_include_file("pythonic/%s/slice.hpp" % pythran_builtins) env.add_include_file("<new>") # for placement new @@ -223,5 +223,5 @@ def include_pythran_generic(env): env.add_include_file("pythonic/types/uint%d.hpp" % i) env.add_include_file("pythonic/types/int%d.hpp" % i) for t in ("float", "float32", "float64", "set", "slice", "tuple", "int", - "complex", "complex64", "complex128"): + "complex", "complex64", "complex128"): env.add_include_file("pythonic/types/%s.hpp" % t) diff --git a/contrib/tools/cython/Cython/Compiler/Scanning.pxd b/contrib/tools/cython/Cython/Compiler/Scanning.pxd index 8eba7f068e..59593f88a2 100644 --- a/contrib/tools/cython/Cython/Compiler/Scanning.pxd +++ b/contrib/tools/cython/Cython/Compiler/Scanning.pxd @@ -4,27 +4,27 @@ import cython from ..Plex.Scanners cimport Scanner -cdef unicode any_string_prefix, IDENT - -cdef get_lexicon() -cdef initial_compile_time_env() - +cdef unicode any_string_prefix, IDENT + +cdef get_lexicon() +cdef initial_compile_time_env() + cdef class Method: cdef object name - cdef dict kwargs - cdef readonly object __name__ # for tracing the scanner + cdef dict kwargs + cdef readonly object __name__ # for tracing the scanner + +## methods commented with '##' out are used by Parsing.py when compiled. -## methods commented with '##' out are used by Parsing.py when compiled. - -@cython.final +@cython.final cdef class CompileTimeScope: cdef public dict entries cdef public CompileTimeScope outer - ##cdef declare(self, name, value) - ##cdef lookup_here(self, name) - ##cpdef lookup(self, name) + ##cdef declare(self, name, value) + ##cdef lookup_here(self, name) + ##cpdef lookup(self, name) -@cython.final +@cython.final cdef class PyrexScanner(Scanner): cdef public context cdef public list included_files @@ -53,15 +53,15 @@ cdef class PyrexScanner(Scanner): @cython.locals(current_level=cython.long, new_level=cython.long) cpdef indentation_action(self, text) #cpdef eof_action(self, text) - ##cdef next(self) - ##cdef peek(self) + ##cdef next(self) + ##cdef peek(self) #cpdef put_back(self, sy, systring) #cdef unread(self, token, value) - ##cdef bint expect(self, what, message = *) except -2 - ##cdef expect_keyword(self, what, message = *) - ##cdef expected(self, what, message = *) - ##cdef expect_indent(self) - ##cdef expect_dedent(self) - ##cdef expect_newline(self, message=*, bint ignore_semicolon=*) - ##cdef int enter_async(self) except -1 - ##cdef int exit_async(self) except -1 + ##cdef bint expect(self, what, message = *) except -2 + ##cdef expect_keyword(self, what, message = *) + ##cdef expected(self, what, message = *) + ##cdef expect_indent(self) + ##cdef expect_dedent(self) + ##cdef expect_newline(self, message=*, bint ignore_semicolon=*) + ##cdef int enter_async(self) except -1 + ##cdef int exit_async(self) except -1 diff --git a/contrib/tools/cython/Cython/Compiler/Scanning.py b/contrib/tools/cython/Cython/Compiler/Scanning.py index 78ad205d04..c721bba69b 100644 --- a/contrib/tools/cython/Cython/Compiler/Scanning.py +++ b/contrib/tools/cython/Cython/Compiler/Scanning.py @@ -5,11 +5,11 @@ from __future__ import absolute_import -import cython -cython.declare(make_lexicon=object, lexicon=object, - print_function=object, error=object, warning=object, - os=object, platform=object) - +import cython +cython.declare(make_lexicon=object, lexicon=object, + print_function=object, error=object, warning=object, + os=object, platform=object) + import os import platform @@ -27,14 +27,14 @@ scanner_dump_file = None lexicon = None - + def get_lexicon(): global lexicon if not lexicon: lexicon = make_lexicon() return lexicon - + #------------------------------------------------------------------ py_reserved_words = [ @@ -50,22 +50,22 @@ pyx_reserved_words = py_reserved_words + [ "cimport", "DEF", "IF", "ELIF", "ELSE" ] - + class Method(object): - def __init__(self, name, **kwargs): + def __init__(self, name, **kwargs): self.name = name - self.kwargs = kwargs or None - self.__name__ = name # for Plex tracing + self.kwargs = kwargs or None + self.__name__ = name # for Plex tracing def __call__(self, stream, text): - method = getattr(stream, self.name) - # self.kwargs is almost always unused => avoid call overhead - return method(text, **self.kwargs) if self.kwargs is not None else method(text) + method = getattr(stream, self.name) + # self.kwargs is almost always unused => avoid call overhead + return method(text, **self.kwargs) if self.kwargs is not None else method(text) def __copy__(self): return self # immutable, no need to copy - + def __deepcopy__(self, memo): return self # immutable, no need to copy @@ -74,7 +74,7 @@ class Method(object): class CompileTimeScope(object): - def __init__(self, outer=None): + def __init__(self, outer=None): self.entries = {} self.outer = outer @@ -100,10 +100,10 @@ class CompileTimeScope(object): else: raise - + def initial_compile_time_env(): benv = CompileTimeScope() - names = ('UNAME_SYSNAME', 'UNAME_NODENAME', 'UNAME_RELEASE', 'UNAME_VERSION', 'UNAME_MACHINE') + names = ('UNAME_SYSNAME', 'UNAME_NODENAME', 'UNAME_RELEASE', 'UNAME_VERSION', 'UNAME_MACHINE') for name, value in zip(names, platform.uname()): benv.declare(name, value) try: @@ -111,17 +111,17 @@ def initial_compile_time_env(): except ImportError: import builtins - names = ( - 'False', 'True', - 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', - 'chr', 'cmp', 'complex', 'dict', 'divmod', 'enumerate', 'filter', - 'float', 'format', 'frozenset', 'hash', 'hex', 'int', 'len', - 'list', 'map', 'max', 'min', 'oct', 'ord', 'pow', 'range', - 'repr', 'reversed', 'round', 'set', 'slice', 'sorted', 'str', - 'sum', 'tuple', 'zip', - ### defined below in a platform independent way - # 'long', 'unicode', 'reduce', 'xrange' - ) + names = ( + 'False', 'True', + 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', + 'chr', 'cmp', 'complex', 'dict', 'divmod', 'enumerate', 'filter', + 'float', 'format', 'frozenset', 'hash', 'hex', 'int', 'len', + 'list', 'map', 'max', 'min', 'oct', 'ord', 'pow', 'range', + 'repr', 'reversed', 'round', 'set', 'slice', 'sorted', 'str', + 'sum', 'tuple', 'zip', + ### defined below in a platform independent way + # 'long', 'unicode', 'reduce', 'xrange' + ) for name in names: try: @@ -129,26 +129,26 @@ def initial_compile_time_env(): except AttributeError: # ignore, likely Py3 pass - - # Py2/3 adaptations - from functools import reduce - benv.declare('reduce', reduce) - benv.declare('unicode', getattr(builtins, 'unicode', getattr(builtins, 'str'))) - benv.declare('long', getattr(builtins, 'long', getattr(builtins, 'int'))) - benv.declare('xrange', getattr(builtins, 'xrange', getattr(builtins, 'range'))) - + + # Py2/3 adaptations + from functools import reduce + benv.declare('reduce', reduce) + benv.declare('unicode', getattr(builtins, 'unicode', getattr(builtins, 'str'))) + benv.declare('long', getattr(builtins, 'long', getattr(builtins, 'int'))) + benv.declare('xrange', getattr(builtins, 'xrange', getattr(builtins, 'range'))) + denv = CompileTimeScope(benv) return denv - + #------------------------------------------------------------------ class SourceDescriptor(object): """ A SourceDescriptor should be considered immutable. """ - filename = None - + filename = None + _file_type = 'pyx' _escaped_description = None @@ -168,11 +168,11 @@ class SourceDescriptor(object): def get_escaped_description(self): if self._escaped_description is None: - esc_desc = \ + esc_desc = \ self.get_description().encode('ASCII', 'replace').decode("ASCII") # Use forward slashes on Windows since these paths - # will be used in the #line directives in the C/C++ files. - self._escaped_description = esc_desc.replace('\\', '/') + # will be used in the #line directives in the C/C++ files. + self._escaped_description = esc_desc.replace('\\', '/') return self._escaped_description def __gt__(self, other): @@ -198,7 +198,7 @@ class SourceDescriptor(object): def __copy__(self): return self # immutable, no need to copy - + def __deepcopy__(self, memo): return self # immutable, no need to copy @@ -232,10 +232,10 @@ class FileSourceDescriptor(SourceDescriptor): return lines except KeyError: pass - - with Utils.open_source_file(self.filename, encoding=encoding, error_handling=error_handling) as f: + + with Utils.open_source_file(self.filename, encoding=encoding, error_handling=error_handling) as f: lines = list(f) - + if key in self._lines: self._lines[key] = lines else: @@ -272,7 +272,7 @@ class FileSourceDescriptor(SourceDescriptor): def __repr__(self): return "<FileSourceDescriptor:%s>" % self.filename - + class StringSourceDescriptor(SourceDescriptor): """ Instances of this class can be used instead of a filenames if the @@ -288,8 +288,8 @@ class StringSourceDescriptor(SourceDescriptor): if not encoding: return self.codelines else: - return [line.encode(encoding, error_handling).decode(encoding) - for line in self.codelines] + return [line.encode(encoding, error_handling).decode(encoding) + for line in self.codelines] def get_description(self): return self.name @@ -311,7 +311,7 @@ class StringSourceDescriptor(SourceDescriptor): def __repr__(self): return "<StringSourceDescriptor:%s>" % self.name - + #------------------------------------------------------------------ class PyrexScanner(Scanner): @@ -321,8 +321,8 @@ class PyrexScanner(Scanner): # compile_time_eval boolean In a true conditional compilation context # compile_time_expr boolean In a compile-time expression context - def __init__(self, file, filename, parent_scanner=None, - scope=None, context=None, source_encoding=None, parse_comments=True, initial_pos=None): + def __init__(self, file, filename, parent_scanner=None, + scope=None, context=None, source_encoding=None, parse_comments=True, initial_pos=None): Scanner.__init__(self, get_lexicon(), file, filename, initial_pos) if filename.is_python_file(): @@ -349,7 +349,7 @@ class PyrexScanner(Scanner): self.compile_time_env = initial_compile_time_env() self.compile_time_eval = 1 self.compile_time_expr = 0 - if getattr(context.options, 'compile_time_env', None): + if getattr(context.options, 'compile_time_env', None): self.compile_time_env.update(context.options.compile_time_env) self.parse_comments = parse_comments self.source_encoding = source_encoding @@ -366,18 +366,18 @@ class PyrexScanner(Scanner): if self.parse_comments: self.produce('commentline', text) - def strip_underscores(self, text, symbol): - self.produce(symbol, text.replace('_', '')) - + def strip_underscores(self, text, symbol): + self.produce(symbol, text.replace('_', '')) + def current_level(self): return self.indentation_stack[-1] def open_bracket_action(self, text): - self.bracket_nesting_level += 1 + self.bracket_nesting_level += 1 return text def close_bracket_action(self, text): - self.bracket_nesting_level -= 1 + self.bracket_nesting_level -= 1 return text def newline_action(self, text): @@ -453,7 +453,7 @@ class PyrexScanner(Scanner): sy, systring = self.read() except UnrecognizedInput: self.error("Unrecognized character") - return # just a marker, error() always raises + return # just a marker, error() always raises if sy == IDENT: if systring in self.keywords: if systring == u'print' and print_function in self.context.future_directives: @@ -462,7 +462,7 @@ class PyrexScanner(Scanner): self.keywords.discard('exec') else: sy = systring - systring = self.context.intern_ustring(systring) + systring = self.context.intern_ustring(systring) self.sy = sy self.systring = systring if False: # debug_scanner: @@ -490,27 +490,27 @@ class PyrexScanner(Scanner): # This method should be added to Plex self.queue.insert(0, (token, value)) - def error(self, message, pos=None, fatal=True): + def error(self, message, pos=None, fatal=True): if pos is None: pos = self.position() if self.sy == 'INDENT': - error(pos, "Possible inconsistent indentation") + error(pos, "Possible inconsistent indentation") err = error(pos, message) if fatal: raise err - def expect(self, what, message=None): + def expect(self, what, message=None): if self.sy == what: self.next() else: self.expected(what, message) - def expect_keyword(self, what, message=None): + def expect_keyword(self, what, message=None): if self.sy == IDENT and self.systring == what: self.next() else: self.expected(what, message) - def expected(self, what, message=None): + def expected(self, what, message=None): if message: self.error(message) else: @@ -521,10 +521,10 @@ class PyrexScanner(Scanner): self.error("Expected '%s', found '%s'" % (what, found)) def expect_indent(self): - self.expect('INDENT', "Expected an increase in indentation level") + self.expect('INDENT', "Expected an increase in indentation level") def expect_dedent(self): - self.expect('DEDENT', "Expected a decrease in indentation level") + self.expect('DEDENT', "Expected a decrease in indentation level") def expect_newline(self, message="Expected a newline", ignore_semicolon=False): # Expect either a newline or end of file @@ -536,18 +536,18 @@ class PyrexScanner(Scanner): self.expect('NEWLINE', message) if useless_trailing_semicolon is not None: warning(useless_trailing_semicolon, "useless trailing semicolon") - - def enter_async(self): - self.async_enabled += 1 - if self.async_enabled == 1: - self.keywords.add('async') - self.keywords.add('await') - - def exit_async(self): - assert self.async_enabled > 0 - self.async_enabled -= 1 - if not self.async_enabled: - self.keywords.discard('await') - self.keywords.discard('async') - if self.sy in ('async', 'await'): - self.sy, self.systring = IDENT, self.context.intern_ustring(self.sy) + + def enter_async(self): + self.async_enabled += 1 + if self.async_enabled == 1: + self.keywords.add('async') + self.keywords.add('await') + + def exit_async(self): + assert self.async_enabled > 0 + self.async_enabled -= 1 + if not self.async_enabled: + self.keywords.discard('await') + self.keywords.discard('async') + if self.sy in ('async', 'await'): + self.sy, self.systring = IDENT, self.context.intern_ustring(self.sy) diff --git a/contrib/tools/cython/Cython/Compiler/StringEncoding.py b/contrib/tools/cython/Cython/Compiler/StringEncoding.py index ee2df88a2f..c37e8aab79 100644 --- a/contrib/tools/cython/Cython/Compiler/StringEncoding.py +++ b/contrib/tools/cython/Cython/Compiler/StringEncoding.py @@ -8,10 +8,10 @@ import re import sys if sys.version_info[0] >= 3: - _unicode, _str, _bytes, _unichr = str, str, bytes, chr + _unicode, _str, _bytes, _unichr = str, str, bytes, chr IS_PYTHON3 = True else: - _unicode, _str, _bytes, _unichr = unicode, str, str, unichr + _unicode, _str, _bytes, _unichr = unicode, str, str, unichr IS_PYTHON3 = False empty_bytes = _bytes() @@ -39,13 +39,13 @@ class UnicodeLiteralBuilder(object): # wide Unicode character on narrow platform => replace # by surrogate pair char_number -= 0x10000 - self.chars.append( _unichr((char_number // 1024) + 0xD800) ) - self.chars.append( _unichr((char_number % 1024) + 0xDC00) ) + self.chars.append( _unichr((char_number // 1024) + 0xD800) ) + self.chars.append( _unichr((char_number % 1024) + 0xDC00) ) else: - self.chars.append( _unichr(char_number) ) + self.chars.append( _unichr(char_number) ) else: def append_charval(self, char_number): - self.chars.append( _unichr(char_number) ) + self.chars.append( _unichr(char_number) ) def append_uescape(self, char_number, escape_string): self.append_charval(char_number) @@ -71,14 +71,14 @@ class BytesLiteralBuilder(object): self.chars.append(characters) def append_charval(self, char_number): - self.chars.append( _unichr(char_number).encode('ISO-8859-1') ) + self.chars.append( _unichr(char_number).encode('ISO-8859-1') ) def append_uescape(self, char_number, escape_string): self.append(escape_string) def getstring(self): # this *must* return a byte string! - return bytes_literal(join_bytes(self.chars), self.target_encoding) + return bytes_literal(join_bytes(self.chars), self.target_encoding) def getchar(self): # this *must* return a byte string! @@ -135,10 +135,10 @@ class EncodedString(_unicode): def contains_surrogates(self): return string_contains_surrogates(self) - def as_utf8_string(self): - return bytes_literal(self.utf8encode(), 'utf8') + def as_utf8_string(self): + return bytes_literal(self.utf8encode(), 'utf8') + - def string_contains_surrogates(ustring): """ Check if the unicode string contains surrogate code points @@ -207,18 +207,18 @@ class BytesLiteral(_bytes): is_unicode = False - def as_c_string_literal(self): - value = split_string_literal(escape_byte_string(self)) - return '"%s"' % value - - -def bytes_literal(s, encoding): - assert isinstance(s, bytes) - s = BytesLiteral(s) - s.encoding = encoding - return s - - + def as_c_string_literal(self): + value = split_string_literal(escape_byte_string(self)) + return '"%s"' % value + + +def bytes_literal(s, encoding): + assert isinstance(s, bytes) + s = BytesLiteral(s) + s.encoding = encoding + return s + + def encoded_string(s, encoding): assert isinstance(s, (_unicode, bytes)) s = EncodedString(s) @@ -338,7 +338,7 @@ def split_string_literal(s, limit=2000): def encode_pyunicode_string(s): """Create Py_UNICODE[] representation of a given unicode string. """ - s = list(map(ord, s)) + [0] + s = list(map(ord, s)) + [0] if sys.maxunicode >= 0x10000: # Wide build or Py3.3 utf16, utf32 = [], s @@ -360,4 +360,4 @@ def encode_pyunicode_string(s): if utf16 == utf32: utf16 = [] - return ",".join(map(_unicode, utf16)), ",".join(map(_unicode, utf32)) + return ",".join(map(_unicode, utf16)), ",".join(map(_unicode, utf32)) diff --git a/contrib/tools/cython/Cython/Compiler/Symtab.py b/contrib/tools/cython/Cython/Compiler/Symtab.py index dabe67f573..7361a55aea 100644 --- a/contrib/tools/cython/Cython/Compiler/Symtab.py +++ b/contrib/tools/cython/Cython/Compiler/Symtab.py @@ -7,12 +7,12 @@ from __future__ import absolute_import import re import copy import operator - -try: - import __builtin__ as builtins -except ImportError: # Py3 - import builtins - + +try: + import __builtin__ as builtins +except ImportError: # Py3 + import builtins + from .Errors import warning, error, InternalError from .StringEncoding import EncodedString from . import Options, Naming @@ -21,8 +21,8 @@ from .PyrexTypes import py_object_type, unspecified_type from .TypeSlots import ( pyfunction_signature, pymethod_signature, richcmp_special_methods, get_special_method_signature, get_property_accessor_signature) -from . import Future - +from . import Future + from . import Code iso_c99_keywords = set( @@ -232,13 +232,13 @@ class Entry(object): def all_entries(self): return [self] + self.inner_entries - def __lt__(left, right): - if isinstance(left, Entry) and isinstance(right, Entry): - return (left.name, left.cname) < (right.name, right.cname) - else: - return NotImplemented + def __lt__(left, right): + if isinstance(left, Entry) and isinstance(right, Entry): + return (left.name, left.cname) < (right.name, right.cname) + else: + return NotImplemented + - class InnerEntry(Entry): """ An entry in a closure scope that represents the real outer Entry. @@ -326,7 +326,7 @@ class Scope(object): self.name = name self.outer_scope = outer_scope self.parent_scope = parent_scope - mangled_name = "%d%s_" % (len(name), name.replace('.', '_dot_')) + mangled_name = "%d%s_" % (len(name), name.replace('.', '_dot_')) qual_scope = self.qualifying_scope() if qual_scope: self.qualified_name = qual_scope.qualify_name(name) @@ -361,7 +361,7 @@ class Scope(object): def merge_in(self, other, merge_unused=True, whitelist=None): # Use with care... entries = [] - for name, entry in other.entries.items(): + for name, entry in other.entries.items(): if not whitelist or name in whitelist: if entry.used or merge_unused: entries.append((name, entry)) @@ -463,11 +463,11 @@ class Scope(object): if cpp_override_allowed: # C++ function/method overrides with different signatures are ok. - pass + pass elif self.is_cpp_class_scope and entries[name].is_inherited: # Likewise ignore inherited classes. pass - elif visibility == 'extern': + elif visibility == 'extern': # Silenced outside of "cdef extern" blocks, until we have a safe way to # prevent pxd-defined cpdef functions from ending up here. warning(pos, "'%s' redeclared " % name, 1 if self.in_cinclude else 0) @@ -531,19 +531,19 @@ class Scope(object): def declare_typedef(self, name, base_type, pos, cname = None, visibility = 'private', api = 0): if not cname: - if self.in_cinclude or (visibility != 'private' or api): + if self.in_cinclude or (visibility != 'private' or api): cname = name else: cname = self.mangle(Naming.type_prefix, name) try: - if self.is_cpp_class_scope: - namespace = self.outer_scope.lookup(self.name).type - else: - namespace = None + if self.is_cpp_class_scope: + namespace = self.outer_scope.lookup(self.name).type + else: + namespace = None type = PyrexTypes.create_typedef_type(name, base_type, cname, - (visibility == 'extern'), - namespace) - except ValueError as e: + (visibility == 'extern'), + namespace) + except ValueError as e: error(pos, e.args[0]) type = PyrexTypes.error_type entry = self.declare_type(name, type, pos, cname, @@ -582,8 +582,8 @@ class Scope(object): if scope: entry.type.scope = scope self.type_entries.append(entry) - if self.is_cpp_class_scope: - entry.type.namespace = self.outer_scope.lookup(self.name).type + if self.is_cpp_class_scope: + entry.type.namespace = self.outer_scope.lookup(self.name).type return entry def declare_cpp_class(self, name, scope, @@ -633,7 +633,7 @@ class Scope(object): else: declare_inherited_attributes(entry, base_class.base_classes) entry.type.scope.declare_inherited_cpp_attributes(base_class) - if scope: + if scope: declare_inherited_attributes(entry, base_classes) scope.declare_var(name="this", cname="this", type=PyrexTypes.CPtrType(entry.type), pos=entry.pos) if self.is_cpp_class_scope: @@ -654,16 +654,16 @@ class Scope(object): visibility = 'private', api = 0, create_wrapper = 0): if name: if not cname: - if (self.in_cinclude or visibility == 'public' - or visibility == 'extern' or api): + if (self.in_cinclude or visibility == 'public' + or visibility == 'extern' or api): cname = name else: cname = self.mangle(Naming.type_prefix, name) - if self.is_cpp_class_scope: - namespace = self.outer_scope.lookup(self.name).type - else: - namespace = None - type = PyrexTypes.CEnumType(name, cname, typedef_flag, namespace) + if self.is_cpp_class_scope: + namespace = self.outer_scope.lookup(self.name).type + else: + namespace = None + type = PyrexTypes.CEnumType(name, cname, typedef_flag, namespace) else: type = PyrexTypes.c_anon_enum_type entry = self.declare_type(name, type, pos, cname = cname, @@ -673,9 +673,9 @@ class Scope(object): self.sue_entries.append(entry) return entry - def declare_tuple_type(self, pos, components): - return self.outer_scope.declare_tuple_type(pos, components) - + def declare_tuple_type(self, pos, components): + return self.outer_scope.declare_tuple_type(pos, components) + def declare_var(self, name, type, pos, cname = None, visibility = 'private', api = 0, in_pxd = 0, is_cdef = 0): @@ -751,8 +751,8 @@ class Scope(object): self.pyfunc_entries.append(entry) def declare_cfunction(self, name, type, pos, - cname=None, visibility='private', api=0, in_pxd=0, - defining=0, modifiers=(), utility_code=None, overridable=False): + cname=None, visibility='private', api=0, in_pxd=0, + defining=0, modifiers=(), utility_code=None, overridable=False): # Add an entry for a C function. if not cname: if visibility != 'private' or api: @@ -761,18 +761,18 @@ class Scope(object): cname = self.mangle(Naming.func_prefix, name) entry = self.lookup_here(name) if entry: - if not in_pxd and visibility != entry.visibility and visibility == 'extern': - # Previously declared, but now extern => treat this - # as implementing the function, using the new cname - defining = True - visibility = entry.visibility - entry.cname = cname - entry.func_cname = cname + if not in_pxd and visibility != entry.visibility and visibility == 'extern': + # Previously declared, but now extern => treat this + # as implementing the function, using the new cname + defining = True + visibility = entry.visibility + entry.cname = cname + entry.func_cname = cname if visibility != 'private' and visibility != entry.visibility: - warning(pos, "Function '%s' previously declared as '%s', now as '%s'" % (name, entry.visibility, visibility), 1) - if overridable != entry.is_overridable: - warning(pos, "Function '%s' previously declared as '%s'" % ( - name, 'cpdef' if overridable else 'cdef'), 1) + warning(pos, "Function '%s' previously declared as '%s', now as '%s'" % (name, entry.visibility, visibility), 1) + if overridable != entry.is_overridable: + warning(pos, "Function '%s' previously declared as '%s'" % ( + name, 'cpdef' if overridable else 'cdef'), 1) if entry.type.same_as(type): # Fix with_gil vs nogil. entry.type = entry.type.with_with_gil(type.with_gil) @@ -805,7 +805,7 @@ class Scope(object): else: entry = self.add_cfunction(name, type, pos, cname, visibility, modifiers) entry.func_cname = cname - entry.is_overridable = overridable + entry.is_overridable = overridable if in_pxd and visibility != 'extern': entry.defined_in_pxd = 1 if api: @@ -819,14 +819,14 @@ class Scope(object): if utility_code: assert not entry.utility_code, "duplicate utility code definition in entry %s (%s)" % (name, cname) entry.utility_code = utility_code - if overridable: - # names of cpdef functions can be used as variables and can be assigned to - var_entry = Entry(name, cname, py_object_type) # FIXME: cname? + if overridable: + # names of cpdef functions can be used as variables and can be assigned to + var_entry = Entry(name, cname, py_object_type) # FIXME: cname? var_entry.qualified_name = self.qualify_name(name) - var_entry.is_variable = 1 - var_entry.is_pyglobal = 1 - var_entry.scope = entry.scope - entry.as_variable = var_entry + var_entry.is_variable = 1 + var_entry.is_pyglobal = 1 + var_entry.scope = entry.scope + entry.as_variable = var_entry type.entry = entry return entry @@ -903,34 +903,34 @@ class Scope(object): obj_type = operands[0].type method = obj_type.scope.lookup("operator%s" % operator) if method is not None: - arg_types = [arg.type for arg in operands[1:]] - res = PyrexTypes.best_match([arg.type for arg in operands[1:]], - method.all_alternatives()) + arg_types = [arg.type for arg in operands[1:]] + res = PyrexTypes.best_match([arg.type for arg in operands[1:]], + method.all_alternatives()) if res is not None: return res function = self.lookup("operator%s" % operator) - function_alternatives = [] - if function is not None: - function_alternatives = function.all_alternatives() - - # look-up nonmember methods listed within a class - method_alternatives = [] - if len(operands)==2: # binary operators only - for n in range(2): - if operands[n].type.is_cpp_class: - obj_type = operands[n].type - method = obj_type.scope.lookup("operator%s" % operator) - if method is not None: - method_alternatives += method.all_alternatives() - - if (not method_alternatives) and (not function_alternatives): + function_alternatives = [] + if function is not None: + function_alternatives = function.all_alternatives() + + # look-up nonmember methods listed within a class + method_alternatives = [] + if len(operands)==2: # binary operators only + for n in range(2): + if operands[n].type.is_cpp_class: + obj_type = operands[n].type + method = obj_type.scope.lookup("operator%s" % operator) + if method is not None: + method_alternatives += method.all_alternatives() + + if (not method_alternatives) and (not function_alternatives): return None - - # select the unique alternatives - all_alternatives = list(set(method_alternatives + function_alternatives)) - - return PyrexTypes.best_match([arg.type for arg in operands], - all_alternatives) + + # select the unique alternatives + all_alternatives = list(set(method_alternatives + function_alternatives)) + + return PyrexTypes.best_match([arg.type for arg in operands], + all_alternatives) def lookup_operator_for_types(self, pos, operator, types): from .Nodes import Node @@ -942,9 +942,9 @@ class Scope(object): def use_utility_code(self, new_code): self.global_scope().use_utility_code(new_code) - def use_entry_utility_code(self, entry): - self.global_scope().use_entry_utility_code(entry) - + def use_entry_utility_code(self, entry): + self.global_scope().use_entry_utility_code(entry) + def defines_any(self, names): # Test whether any of the given names are defined in this scope. for name in names: @@ -970,8 +970,8 @@ class Scope(object): else: return outer.is_cpp() - def add_include_file(self, filename, verbatim_include=None, late=False): - self.outer_scope.add_include_file(filename, verbatim_include, late) + def add_include_file(self, filename, verbatim_include=None, late=False): + self.outer_scope.add_include_file(filename, verbatim_include, late) class PreImportScope(Scope): @@ -1000,16 +1000,16 @@ class BuiltinScope(Scope): Scope.__init__(self, "__builtin__", PreImportScope(), None) self.type_names = {} - for name, definition in sorted(self.builtin_entries.items()): + for name, definition in sorted(self.builtin_entries.items()): cname, type = definition self.declare_var(name, type, None, cname) - def lookup(self, name, language_level=None, str_is_str=None): - # 'language_level' and 'str_is_str' are passed by ModuleScope - if name == 'str': - if str_is_str is None: - str_is_str = language_level in (None, 2) - if not str_is_str: + def lookup(self, name, language_level=None, str_is_str=None): + # 'language_level' and 'str_is_str' are passed by ModuleScope + if name == 'str': + if str_is_str is None: + str_is_str = language_level in (None, 2) + if not str_is_str: name = 'unicode' return Scope.lookup(self, name) @@ -1023,12 +1023,12 @@ class BuiltinScope(Scope): else: warning(pos, "undeclared name not builtin: %s" % name, 2) - def declare_builtin_cfunction(self, name, type, cname, python_equiv=None, utility_code=None): + def declare_builtin_cfunction(self, name, type, cname, python_equiv=None, utility_code=None): # If python_equiv == "*", the Python equivalent has the same name # as the entry, otherwise it has the name specified by python_equiv. name = EncodedString(name) entry = self.declare_cfunction(name, type, None, cname, visibility='extern', - utility_code=utility_code) + utility_code=utility_code) if python_equiv: if python_equiv == "*": python_equiv = name @@ -1058,14 +1058,14 @@ class BuiltinScope(Scope): var_entry = Entry(name = entry.name, type = self.lookup('type').type, # make sure "type" is the first type declared... pos = entry.pos, - cname = entry.type.typeptr_cname) + cname = entry.type.typeptr_cname) var_entry.qualified_name = self.qualify_name(name) var_entry.is_variable = 1 var_entry.is_cglobal = 1 var_entry.is_readonly = 1 var_entry.is_builtin = 1 var_entry.utility_code = utility_code - var_entry.scope = self + var_entry.scope = self if Options.cache_builtins: var_entry.is_const = True entry.as_variable = var_entry @@ -1134,7 +1134,7 @@ class ModuleScope(Scope): is_module_scope = 1 has_import_star = 0 is_cython_builtin = 0 - old_style_globals = 0 + old_style_globals = 0 def __init__(self, name, parent_module, context): from . import Builtin @@ -1168,7 +1168,7 @@ class ModuleScope(Scope): self.cached_builtins = [] self.undeclared_cached_builtins = [] self.namespace_cname = self.module_cname - self._cached_tuple_types = {} + self._cached_tuple_types = {} for var_name in ['__builtins__', '__name__', '__file__', '__doc__', '__path__', '__spec__', '__loader__', '__package__', '__cached__']: self.declare_var(EncodedString(var_name), py_object_type, None) @@ -1180,39 +1180,39 @@ class ModuleScope(Scope): def global_scope(self): return self - def lookup(self, name, language_level=None, str_is_str=None): + def lookup(self, name, language_level=None, str_is_str=None): entry = self.lookup_here(name) if entry is not None: return entry - if language_level is None: - language_level = self.context.language_level if self.context is not None else 3 - if str_is_str is None: - str_is_str = language_level == 2 or ( - self.context is not None and Future.unicode_literals not in self.context.future_directives) - - return self.outer_scope.lookup(name, language_level=language_level, str_is_str=str_is_str) - - def declare_tuple_type(self, pos, components): - components = tuple(components) - try: - ttype = self._cached_tuple_types[components] - except KeyError: - ttype = self._cached_tuple_types[components] = PyrexTypes.c_tuple_type(components) - cname = ttype.cname - entry = self.lookup_here(cname) - if not entry: - scope = StructOrUnionScope(cname) - for ix, component in enumerate(components): - scope.declare_var(name="f%s" % ix, type=component, pos=pos) - struct_entry = self.declare_struct_or_union( - cname + '_struct', 'struct', scope, typedef_flag=True, pos=pos, cname=cname) - self.type_entries.remove(struct_entry) - ttype.struct_entry = struct_entry - entry = self.declare_type(cname, ttype, pos, cname) - ttype.entry = entry - return entry - + if language_level is None: + language_level = self.context.language_level if self.context is not None else 3 + if str_is_str is None: + str_is_str = language_level == 2 or ( + self.context is not None and Future.unicode_literals not in self.context.future_directives) + + return self.outer_scope.lookup(name, language_level=language_level, str_is_str=str_is_str) + + def declare_tuple_type(self, pos, components): + components = tuple(components) + try: + ttype = self._cached_tuple_types[components] + except KeyError: + ttype = self._cached_tuple_types[components] = PyrexTypes.c_tuple_type(components) + cname = ttype.cname + entry = self.lookup_here(cname) + if not entry: + scope = StructOrUnionScope(cname) + for ix, component in enumerate(components): + scope.declare_var(name="f%s" % ix, type=component, pos=pos) + struct_entry = self.declare_struct_or_union( + cname + '_struct', 'struct', scope, typedef_flag=True, pos=pos, cname=cname) + self.type_entries.remove(struct_entry) + ttype.struct_entry = struct_entry + entry = self.declare_type(cname, ttype, pos, cname) + ttype.entry = entry + return entry + def declare_builtin(self, name, pos): if not hasattr(builtins, name) \ and name not in Code.non_portable_builtins_map \ @@ -1233,10 +1233,10 @@ class ModuleScope(Scope): for entry in self.cached_builtins: if entry.name == name: return entry - if name == 'globals' and not self.old_style_globals: - return self.outer_scope.lookup('__Pyx_Globals') - else: - entry = self.declare(None, None, py_object_type, pos, 'private') + if name == 'globals' and not self.old_style_globals: + return self.outer_scope.lookup('__Pyx_Globals') + else: + entry = self.declare(None, None, py_object_type, pos, 'private') if Options.cache_builtins and name not in Code.uncachable_builtins: entry.is_builtin = 1 entry.is_const = 1 # cached @@ -1255,49 +1255,49 @@ class ModuleScope(Scope): # relative imports relative to this module's parent. # Finds and parses the module's .pxd file if the module # has not been referenced before. - relative_to = None - absolute_fallback = False - if relative_level is not None and relative_level > 0: - # explicit relative cimport - # error of going beyond top-level is handled in cimport node - relative_to = self - while relative_level > 0 and relative_to: - relative_to = relative_to.parent_module - relative_level -= 1 - elif relative_level != 0: - # -1 or None: try relative cimport first, then absolute - relative_to = self.parent_module - absolute_fallback = True - + relative_to = None + absolute_fallback = False + if relative_level is not None and relative_level > 0: + # explicit relative cimport + # error of going beyond top-level is handled in cimport node + relative_to = self + while relative_level > 0 and relative_to: + relative_to = relative_to.parent_module + relative_level -= 1 + elif relative_level != 0: + # -1 or None: try relative cimport first, then absolute + relative_to = self.parent_module + absolute_fallback = True + module_scope = self.global_scope() return module_scope.context.find_module( - module_name, relative_to=relative_to, pos=pos, absolute_fallback=absolute_fallback) + module_name, relative_to=relative_to, pos=pos, absolute_fallback=absolute_fallback) def find_submodule(self, name): # Find and return scope for a submodule of this module, # creating a new empty one if necessary. Doesn't parse .pxd. - if '.' in name: - name, submodule = name.split('.', 1) - else: - submodule = None + if '.' in name: + name, submodule = name.split('.', 1) + else: + submodule = None scope = self.lookup_submodule(name) if not scope: - scope = ModuleScope(name, parent_module=self, context=self.context) + scope = ModuleScope(name, parent_module=self, context=self.context) self.module_entries[name] = scope - if submodule: - scope = scope.find_submodule(submodule) + if submodule: + scope = scope.find_submodule(submodule) return scope def lookup_submodule(self, name): # Return scope for submodule of this module, or None. - if '.' in name: - name, submodule = name.split('.', 1) - else: - submodule = None - module = self.module_entries.get(name, None) - if submodule and module is not None: - module = module.lookup_submodule(submodule) - return module + if '.' in name: + name, submodule = name.split('.', 1) + else: + submodule = None + module = self.module_entries.get(name, None) + if submodule and module is not None: + module = module.lookup_submodule(submodule) + return module def add_include_file(self, filename, verbatim_include=None, late=False): """ @@ -1438,8 +1438,8 @@ class ModuleScope(Scope): return entry def declare_cfunction(self, name, type, pos, - cname=None, visibility='private', api=0, in_pxd=0, - defining=0, modifiers=(), utility_code=None, overridable=False): + cname=None, visibility='private', api=0, in_pxd=0, + defining=0, modifiers=(), utility_code=None, overridable=False): if not defining and 'inline' in modifiers: # TODO(github/1736): Make this an error. warning(pos, "Declarations should not be declared inline.", 1) @@ -1449,8 +1449,8 @@ class ModuleScope(Scope): cname = name else: cname = self.mangle(Naming.func_prefix, name) - if visibility == 'extern' and type.optional_arg_count: - error(pos, "Extern functions cannot have default arguments values.") + if visibility == 'extern' and type.optional_arg_count: + error(pos, "Extern functions cannot have default arguments values.") entry = self.lookup_here(name) if entry and entry.defined_in_pxd: if entry.visibility != "private": @@ -1461,9 +1461,9 @@ class ModuleScope(Scope): entry.func_cname = cname entry = Scope.declare_cfunction( self, name, type, pos, - cname=cname, visibility=visibility, api=api, in_pxd=in_pxd, - defining=defining, modifiers=modifiers, utility_code=utility_code, - overridable=overridable) + cname=cname, visibility=visibility, api=api, in_pxd=in_pxd, + defining=defining, modifiers=modifiers, utility_code=utility_code, + overridable=overridable) return entry def declare_global(self, name, pos): @@ -1475,19 +1475,19 @@ class ModuleScope(Scope): if new_code is not None: self.utility_code_list.append(new_code) - def use_entry_utility_code(self, entry): - if entry is None: - return - if entry.utility_code: - self.utility_code_list.append(entry.utility_code) - if entry.utility_code_definition: - self.utility_code_list.append(entry.utility_code_definition) - - def declare_c_class(self, name, pos, defining=0, implementing=0, - module_name=None, base_type=None, objstruct_cname=None, - typeobj_cname=None, typeptr_cname=None, visibility='private', - typedef_flag=0, api=0, check_size=None, - buffer_defaults=None, shadow=0): + def use_entry_utility_code(self, entry): + if entry is None: + return + if entry.utility_code: + self.utility_code_list.append(entry.utility_code) + if entry.utility_code_definition: + self.utility_code_list.append(entry.utility_code_definition) + + def declare_c_class(self, name, pos, defining=0, implementing=0, + module_name=None, base_type=None, objstruct_cname=None, + typeobj_cname=None, typeptr_cname=None, visibility='private', + typedef_flag=0, api=0, check_size=None, + buffer_defaults=None, shadow=0): # If this is a non-extern typedef class, expose the typedef, but use # the non-typedef struct internally to avoid needing forward # declarations for anonymous structs. @@ -1519,8 +1519,8 @@ class ModuleScope(Scope): # Make a new entry if needed # if not entry or shadow: - type = PyrexTypes.PyExtensionType( - name, typedef_flag, base_type, visibility == 'extern', check_size=check_size) + type = PyrexTypes.PyExtensionType( + name, typedef_flag, base_type, visibility == 'extern', check_size=check_size) type.pos = pos type.buffer_defaults = buffer_defaults if objtypedef_cname is not None: @@ -1710,12 +1710,12 @@ class ModuleScope(Scope): var_entry = Entry(name = entry.name, type = Builtin.type_type, pos = entry.pos, - cname = entry.type.typeptr_cname) + cname = entry.type.typeptr_cname) var_entry.qualified_name = entry.qualified_name var_entry.is_variable = 1 var_entry.is_cglobal = 1 var_entry.is_readonly = 1 - var_entry.scope = entry.scope + var_entry.scope = entry.scope entry.as_variable = var_entry def is_cpp(self): @@ -1937,10 +1937,10 @@ class StructOrUnionScope(Scope): return entry def declare_cfunction(self, name, type, pos, - cname=None, visibility='private', api=0, in_pxd=0, - defining=0, modifiers=(), overridable=False): # currently no utility code ... - if overridable: - error(pos, "C struct/union member cannot be declared 'cpdef'") + cname=None, visibility='private', api=0, in_pxd=0, + defining=0, modifiers=(), overridable=False): # currently no utility code ... + if overridable: + error(pos, "C struct/union member cannot be declared 'cpdef'") return self.declare_var(name, type, pos, cname=cname, visibility=visibility) @@ -1975,7 +1975,7 @@ class ClassScope(Scope): py_object_type, [PyrexTypes.CFuncTypeArg("", py_object_type, None)], 0, 0)) entry.utility_code_definition = Code.UtilityCode.load_cached("ClassMethod", "CythonFunction.c") - self.use_entry_utility_code(entry) + self.use_entry_utility_code(entry) entry.is_cfunction = 1 return entry @@ -2050,7 +2050,7 @@ class CClassScope(ClassScope): # getset_table_cname string # has_pyobject_attrs boolean Any PyObject attributes? # has_memoryview_attrs boolean Any memory view attributes? - # has_cpp_class_attrs boolean Any (non-pointer) C++ attributes? + # has_cpp_class_attrs boolean Any (non-pointer) C++ attributes? # has_cyclic_pyobject_attrs boolean Any PyObject attributes that may need GC? # property_entries [Entry] # defined boolean Defined in .pxd file @@ -2062,7 +2062,7 @@ class CClassScope(ClassScope): has_pyobject_attrs = False has_memoryview_attrs = False - has_cpp_class_attrs = False + has_cpp_class_attrs = False has_cyclic_pyobject_attrs = False defined = False implemented = False @@ -2078,7 +2078,7 @@ class CClassScope(ClassScope): def needs_gc(self): # If the type or any of its base types have Python-valued # C attributes, then it needs to participate in GC. - if self.has_cyclic_pyobject_attrs and not self.directives.get('no_gc', False): + if self.has_cyclic_pyobject_attrs and not self.directives.get('no_gc', False): return True base_type = self.parent_type.base_type if base_type and base_type.scope is not None: @@ -2138,8 +2138,8 @@ class CClassScope(ClassScope): self.var_entries.append(entry) if type.is_memoryviewslice: self.has_memoryview_attrs = True - elif type.is_cpp_class: - self.has_cpp_class_attrs = True + elif type.is_cpp_class: + self.has_cpp_class_attrs = True elif type.is_pyobject and (self.is_closure_class_scope or name != '__weakref__'): self.has_pyobject_attrs = True if (not type.is_builtin_type @@ -2155,9 +2155,9 @@ class CClassScope(ClassScope): entry.needs_property = True if not self.is_closure_class_scope and name == "__weakref__": error(pos, "Special attribute __weakref__ cannot be exposed to Python") - if not (type.is_pyobject or type.can_coerce_to_pyobject(self)): - # we're not testing for coercion *from* Python here - that would fail later - error(pos, "C attribute of type '%s' cannot be accessed from Python" % type) + if not (type.is_pyobject or type.can_coerce_to_pyobject(self)): + # we're not testing for coercion *from* Python here - that would fail later + error(pos, "C attribute of type '%s' cannot be accessed from Python" % type) else: entry.needs_property = False return entry @@ -2218,8 +2218,8 @@ class CClassScope(ClassScope): return entry def declare_cfunction(self, name, type, pos, - cname=None, visibility='private', api=0, in_pxd=0, - defining=0, modifiers=(), utility_code=None, overridable=False): + cname=None, visibility='private', api=0, in_pxd=0, + defining=0, modifiers=(), utility_code=None, overridable=False): if get_special_method_signature(name) and not self.parent_type.is_builtin_type: error(pos, "Special methods must be declared with 'def', not 'cdef'") args = type.args @@ -2250,9 +2250,9 @@ class CClassScope(ClassScope): # TODO(robertwb): Make this an error. warning(pos, "Compatible but non-identical C method '%s' not redeclared " - "in definition part of extension type '%s'. " - "This may cause incorrect vtables to be generated." % ( - name, self.class_name), 2) + "in definition part of extension type '%s'. " + "This may cause incorrect vtables to be generated." % ( + name, self.class_name), 2) warning(entry.pos, "Previous declaration is here", 2) entry = self.add_cfunction(name, type, pos, cname, visibility='ignore', modifiers=modifiers) else: @@ -2263,7 +2263,7 @@ class CClassScope(ClassScope): error(pos, "C method '%s' not previously declared in definition part of" " extension type '%s'" % (name, self.class_name)) - entry = self.add_cfunction(name, type, pos, cname, visibility, modifiers) + entry = self.add_cfunction(name, type, pos, cname, visibility, modifiers) if defining: entry.func_cname = self.mangle(Naming.func_prefix, name) entry.utility_code = utility_code @@ -2293,13 +2293,13 @@ class CClassScope(ClassScope): # equivalent that must be accessible to support bound methods name = EncodedString(name) entry = self.declare_cfunction(name, type, None, cname, visibility='extern', - utility_code=utility_code) + utility_code=utility_code) var_entry = Entry(name, name, py_object_type) var_entry.qualified_name = name var_entry.is_variable = 1 var_entry.is_builtin = 1 var_entry.utility_code = utility_code - var_entry.scope = entry.scope + var_entry.scope = entry.scope entry.as_variable = var_entry return entry @@ -2397,15 +2397,15 @@ class CppClassScope(Scope): entry = self.declare(name, cname, type, pos, visibility) entry.is_variable = 1 if type.is_cfunction and self.type: - if not self.type.get_fused_types(): - entry.func_cname = "%s::%s" % (self.type.empty_declaration_code(), cname) + if not self.type.get_fused_types(): + entry.func_cname = "%s::%s" % (self.type.empty_declaration_code(), cname) if name != "this" and (defining or name != "<init>"): self.var_entries.append(entry) return entry def declare_cfunction(self, name, type, pos, - cname=None, visibility='extern', api=0, in_pxd=0, - defining=0, modifiers=(), utility_code=None, overridable=False): + cname=None, visibility='extern', api=0, in_pxd=0, + defining=0, modifiers=(), utility_code=None, overridable=False): class_name = self.name.split('::')[-1] if name in (class_name, '__init__') and cname is None: cname = "%s__init__%s" % (Naming.func_prefix, class_name) @@ -2469,9 +2469,9 @@ class CppClassScope(Scope): for base_entry in base_scope.cfunc_entries: entry = self.declare_cfunction(base_entry.name, base_entry.type, base_entry.pos, base_entry.cname, - base_entry.visibility, api=0, - modifiers=base_entry.func_modifiers, - utility_code=base_entry.utility_code) + base_entry.visibility, api=0, + modifiers=base_entry.func_modifiers, + utility_code=base_entry.utility_code) entry.is_inherited = 1 for base_entry in base_scope.type_entries: if base_entry.name not in base_templates: @@ -2496,7 +2496,7 @@ class CppClassScope(Scope): e.type.specialize(values), e.pos, e.cname, - utility_code=e.utility_code) + utility_code=e.utility_code) else: scope.declare_var(entry.name, entry.type.specialize(values), diff --git a/contrib/tools/cython/Cython/Compiler/Tests/TestCmdLine.py b/contrib/tools/cython/Cython/Compiler/Tests/TestCmdLine.py index f8862d064a..abc7c0a892 100644 --- a/contrib/tools/cython/Cython/Compiler/Tests/TestCmdLine.py +++ b/contrib/tools/cython/Cython/Compiler/Tests/TestCmdLine.py @@ -1,118 +1,118 @@ - -import sys -from unittest import TestCase -try: - from StringIO import StringIO -except ImportError: - from io import StringIO # doesn't accept 'str' in Py2 - -from .. import Options -from ..CmdLine import parse_command_line - - -class CmdLineParserTest(TestCase): - def setUp(self): - backup = {} - for name, value in vars(Options).items(): - backup[name] = value - self._options_backup = backup - - def tearDown(self): - no_value = object() - for name, orig_value in self._options_backup.items(): - if getattr(Options, name, no_value) != orig_value: - setattr(Options, name, orig_value) - - def test_short_options(self): - options, sources = parse_command_line([ - '-V', '-l', '-+', '-t', '-v', '-v', '-v', '-p', '-D', '-a', '-3', - ]) - self.assertFalse(sources) - self.assertTrue(options.show_version) - self.assertTrue(options.use_listing_file) - self.assertTrue(options.cplus) - self.assertTrue(options.timestamps) - self.assertTrue(options.verbose >= 3) - self.assertTrue(Options.embed_pos_in_docstring) - self.assertFalse(Options.docstrings) - self.assertTrue(Options.annotate) - self.assertEqual(options.language_level, 3) - - options, sources = parse_command_line([ - '-f', '-2', 'source.pyx', - ]) - self.assertTrue(sources) - self.assertTrue(len(sources) == 1) - self.assertFalse(options.timestamps) - self.assertEqual(options.language_level, 2) - - def test_long_options(self): - options, sources = parse_command_line([ - '--version', '--create-listing', '--cplus', '--embed', '--timestamps', - '--verbose', '--verbose', '--verbose', - '--embed-positions', '--no-docstrings', '--annotate', '--lenient', - ]) - self.assertFalse(sources) - self.assertTrue(options.show_version) - self.assertTrue(options.use_listing_file) - self.assertTrue(options.cplus) - self.assertEqual(Options.embed, 'main') - self.assertTrue(options.timestamps) - self.assertTrue(options.verbose >= 3) - self.assertTrue(Options.embed_pos_in_docstring) - self.assertFalse(Options.docstrings) - self.assertTrue(Options.annotate) - self.assertFalse(Options.error_on_unknown_names) - self.assertFalse(Options.error_on_uninitialized) - - options, sources = parse_command_line([ - '--force', 'source.pyx', - ]) - self.assertTrue(sources) - self.assertTrue(len(sources) == 1) - self.assertFalse(options.timestamps) - - def test_options_with_values(self): - options, sources = parse_command_line([ - '--embed=huhu', - '-I/test/include/dir1', '--include-dir=/test/include/dir2', - '--include-dir', '/test/include/dir3', - '--working=/work/dir', - 'source.pyx', - '--output-file=/output/dir', - '--pre-import=/pre/import', - '--cleanup=3', - '--annotate-coverage=cov.xml', - '--gdb-outdir=/gdb/outdir', - '--directive=wraparound=false', - ]) - self.assertEqual(sources, ['source.pyx']) - self.assertEqual(Options.embed, 'huhu') - self.assertEqual(options.include_path, ['/test/include/dir1', '/test/include/dir2', '/test/include/dir3']) - self.assertEqual(options.working_path, '/work/dir') - self.assertEqual(options.output_file, '/output/dir') - self.assertEqual(Options.pre_import, '/pre/import') - self.assertEqual(Options.generate_cleanup_code, 3) - self.assertTrue(Options.annotate) - self.assertEqual(Options.annotate_coverage_xml, 'cov.xml') - self.assertTrue(options.gdb_debug) - self.assertEqual(options.output_dir, '/gdb/outdir') - - def test_errors(self): - def error(*args): - old_stderr = sys.stderr - stderr = sys.stderr = StringIO() - try: - self.assertRaises(SystemExit, parse_command_line, list(args)) - finally: - sys.stderr = old_stderr - self.assertTrue(stderr.getvalue()) - - error('-1') - error('-I') - error('--version=-a') - error('--version=--annotate=true') - error('--working') - error('--verbose=1') - error('--verbose=1') - error('--cleanup') + +import sys +from unittest import TestCase +try: + from StringIO import StringIO +except ImportError: + from io import StringIO # doesn't accept 'str' in Py2 + +from .. import Options +from ..CmdLine import parse_command_line + + +class CmdLineParserTest(TestCase): + def setUp(self): + backup = {} + for name, value in vars(Options).items(): + backup[name] = value + self._options_backup = backup + + def tearDown(self): + no_value = object() + for name, orig_value in self._options_backup.items(): + if getattr(Options, name, no_value) != orig_value: + setattr(Options, name, orig_value) + + def test_short_options(self): + options, sources = parse_command_line([ + '-V', '-l', '-+', '-t', '-v', '-v', '-v', '-p', '-D', '-a', '-3', + ]) + self.assertFalse(sources) + self.assertTrue(options.show_version) + self.assertTrue(options.use_listing_file) + self.assertTrue(options.cplus) + self.assertTrue(options.timestamps) + self.assertTrue(options.verbose >= 3) + self.assertTrue(Options.embed_pos_in_docstring) + self.assertFalse(Options.docstrings) + self.assertTrue(Options.annotate) + self.assertEqual(options.language_level, 3) + + options, sources = parse_command_line([ + '-f', '-2', 'source.pyx', + ]) + self.assertTrue(sources) + self.assertTrue(len(sources) == 1) + self.assertFalse(options.timestamps) + self.assertEqual(options.language_level, 2) + + def test_long_options(self): + options, sources = parse_command_line([ + '--version', '--create-listing', '--cplus', '--embed', '--timestamps', + '--verbose', '--verbose', '--verbose', + '--embed-positions', '--no-docstrings', '--annotate', '--lenient', + ]) + self.assertFalse(sources) + self.assertTrue(options.show_version) + self.assertTrue(options.use_listing_file) + self.assertTrue(options.cplus) + self.assertEqual(Options.embed, 'main') + self.assertTrue(options.timestamps) + self.assertTrue(options.verbose >= 3) + self.assertTrue(Options.embed_pos_in_docstring) + self.assertFalse(Options.docstrings) + self.assertTrue(Options.annotate) + self.assertFalse(Options.error_on_unknown_names) + self.assertFalse(Options.error_on_uninitialized) + + options, sources = parse_command_line([ + '--force', 'source.pyx', + ]) + self.assertTrue(sources) + self.assertTrue(len(sources) == 1) + self.assertFalse(options.timestamps) + + def test_options_with_values(self): + options, sources = parse_command_line([ + '--embed=huhu', + '-I/test/include/dir1', '--include-dir=/test/include/dir2', + '--include-dir', '/test/include/dir3', + '--working=/work/dir', + 'source.pyx', + '--output-file=/output/dir', + '--pre-import=/pre/import', + '--cleanup=3', + '--annotate-coverage=cov.xml', + '--gdb-outdir=/gdb/outdir', + '--directive=wraparound=false', + ]) + self.assertEqual(sources, ['source.pyx']) + self.assertEqual(Options.embed, 'huhu') + self.assertEqual(options.include_path, ['/test/include/dir1', '/test/include/dir2', '/test/include/dir3']) + self.assertEqual(options.working_path, '/work/dir') + self.assertEqual(options.output_file, '/output/dir') + self.assertEqual(Options.pre_import, '/pre/import') + self.assertEqual(Options.generate_cleanup_code, 3) + self.assertTrue(Options.annotate) + self.assertEqual(Options.annotate_coverage_xml, 'cov.xml') + self.assertTrue(options.gdb_debug) + self.assertEqual(options.output_dir, '/gdb/outdir') + + def test_errors(self): + def error(*args): + old_stderr = sys.stderr + stderr = sys.stderr = StringIO() + try: + self.assertRaises(SystemExit, parse_command_line, list(args)) + finally: + sys.stderr = old_stderr + self.assertTrue(stderr.getvalue()) + + error('-1') + error('-I') + error('--version=-a') + error('--version=--annotate=true') + error('--working') + error('--verbose=1') + error('--verbose=1') + error('--cleanup') diff --git a/contrib/tools/cython/Cython/Compiler/Tests/TestFlowControl.py b/contrib/tools/cython/Cython/Compiler/Tests/TestFlowControl.py index cad428607a..443551ab88 100644 --- a/contrib/tools/cython/Cython/Compiler/Tests/TestFlowControl.py +++ b/contrib/tools/cython/Cython/Compiler/Tests/TestFlowControl.py @@ -1,68 +1,68 @@ - -from __future__ import absolute_import - -from copy import deepcopy -from unittest import TestCase - -from Cython.Compiler.FlowControl import ( - NameAssignment, StaticAssignment, Argument, NameDeletion) - - -class FakeType(object): - is_pyobject = True - - -class FakeNode(object): - pos = ('filename.pyx', 1, 2) - cf_state = None - type = FakeType() - - def infer_type(self, scope): - return self.type - - -class FakeEntry(object): - type = FakeType() - - -class TestGraph(TestCase): - def test_deepcopy(self): - lhs, rhs = FakeNode(), FakeNode() - entry = FakeEntry() - entry.pos = lhs.pos - - name_ass = NameAssignment(lhs, rhs, entry) - ass = deepcopy(name_ass) - self.assertTrue(ass.lhs) - self.assertTrue(ass.rhs) - self.assertTrue(ass.entry) - self.assertEqual(ass.pos, name_ass.pos) - self.assertFalse(ass.is_arg) - self.assertFalse(ass.is_deletion) - - static_ass = StaticAssignment(entry) - ass = deepcopy(static_ass) - self.assertTrue(ass.lhs) - self.assertTrue(ass.rhs) - self.assertTrue(ass.entry) - self.assertEqual(ass.pos, static_ass.pos) - self.assertFalse(ass.is_arg) - self.assertFalse(ass.is_deletion) - - arg_ass = Argument(lhs, rhs, entry) - ass = deepcopy(arg_ass) - self.assertTrue(ass.lhs) - self.assertTrue(ass.rhs) - self.assertTrue(ass.entry) - self.assertEqual(ass.pos, arg_ass.pos) - self.assertTrue(ass.is_arg) - self.assertFalse(ass.is_deletion) - - name_del = NameDeletion(lhs, entry) - ass = deepcopy(name_del) - self.assertTrue(ass.lhs) - self.assertTrue(ass.rhs) - self.assertTrue(ass.entry) - self.assertEqual(ass.pos, name_del.pos) - self.assertFalse(ass.is_arg) - self.assertTrue(ass.is_deletion) + +from __future__ import absolute_import + +from copy import deepcopy +from unittest import TestCase + +from Cython.Compiler.FlowControl import ( + NameAssignment, StaticAssignment, Argument, NameDeletion) + + +class FakeType(object): + is_pyobject = True + + +class FakeNode(object): + pos = ('filename.pyx', 1, 2) + cf_state = None + type = FakeType() + + def infer_type(self, scope): + return self.type + + +class FakeEntry(object): + type = FakeType() + + +class TestGraph(TestCase): + def test_deepcopy(self): + lhs, rhs = FakeNode(), FakeNode() + entry = FakeEntry() + entry.pos = lhs.pos + + name_ass = NameAssignment(lhs, rhs, entry) + ass = deepcopy(name_ass) + self.assertTrue(ass.lhs) + self.assertTrue(ass.rhs) + self.assertTrue(ass.entry) + self.assertEqual(ass.pos, name_ass.pos) + self.assertFalse(ass.is_arg) + self.assertFalse(ass.is_deletion) + + static_ass = StaticAssignment(entry) + ass = deepcopy(static_ass) + self.assertTrue(ass.lhs) + self.assertTrue(ass.rhs) + self.assertTrue(ass.entry) + self.assertEqual(ass.pos, static_ass.pos) + self.assertFalse(ass.is_arg) + self.assertFalse(ass.is_deletion) + + arg_ass = Argument(lhs, rhs, entry) + ass = deepcopy(arg_ass) + self.assertTrue(ass.lhs) + self.assertTrue(ass.rhs) + self.assertTrue(ass.entry) + self.assertEqual(ass.pos, arg_ass.pos) + self.assertTrue(ass.is_arg) + self.assertFalse(ass.is_deletion) + + name_del = NameDeletion(lhs, entry) + ass = deepcopy(name_del) + self.assertTrue(ass.lhs) + self.assertTrue(ass.rhs) + self.assertTrue(ass.entry) + self.assertEqual(ass.pos, name_del.pos) + self.assertFalse(ass.is_arg) + self.assertTrue(ass.is_deletion) diff --git a/contrib/tools/cython/Cython/Compiler/Tests/TestGrammar.py b/contrib/tools/cython/Cython/Compiler/Tests/TestGrammar.py index a0ece5c1b5..3dddc960b3 100644 --- a/contrib/tools/cython/Cython/Compiler/Tests/TestGrammar.py +++ b/contrib/tools/cython/Cython/Compiler/Tests/TestGrammar.py @@ -1,129 +1,129 @@ -# mode: run -# tag: syntax - -""" -Uses TreeFragment to test invalid syntax. -""" - -from __future__ import absolute_import - -from ...TestUtils import CythonTest -from ..Errors import CompileError -from .. import ExprNodes - -# Copied from CPython's test_grammar.py -VALID_UNDERSCORE_LITERALS = [ - '0_0_0', - '4_2', - '1_0000_0000', - '0b1001_0100', - '0xffff_ffff', - '0o5_7_7', - '1_00_00.5', - '1_00_00.5j', - '1_00_00.5e5', - '1_00_00j', - '1_00_00e5_1', - '1e1_0', - '.1_4', - '.1_4e1', - '.1_4j', -] - -# Copied from CPython's test_grammar.py -INVALID_UNDERSCORE_LITERALS = [ - # Trailing underscores: - '0_', - '42_', - '1.4j_', - '0b1_', - '0xf_', - '0o5_', - # Underscores in the base selector: - '0_b0', - '0_xf', - '0_o5', - # Underscore right after the base selector: - '0b_0', - '0x_f', - '0o_5', - # Old-style octal, still disallowed: - #'0_7', - #'09_99', - # Special case with exponent: - '0 if 1_Else 1', - # Underscore right before a dot: - '1_.4', - '1_.4j', - # Underscore right after a dot: - '1._4', - '1._4j', - '._5', - # Underscore right after a sign: - '1.0e+_1', - # Multiple consecutive underscores: - '4_______2', - '0.1__4', - '0b1001__0100', - '0xffff__ffff', - '0o5__77', - '1e1__0', - # Underscore right before j: - '1.4_j', - '1.4e5_j', - # Underscore right before e: - '1_e1', - '1.4_e1', - # Underscore right after e: - '1e_1', - '1.4e_1', - # Whitespace in literals - '1_ 2', - '1 _2', - '1_2.2_ 1', - '1_2.2 _1', - '1_2e _1', - '1_2e2 _1', - '1_2e 2_1', -] - - -class TestGrammar(CythonTest): - - def test_invalid_number_literals(self): - for literal in INVALID_UNDERSCORE_LITERALS: - for expression in ['%s', '1 + %s', '%s + 1', '2 * %s', '%s * 2']: - code = 'x = ' + expression % literal - try: - self.fragment(u'''\ - # cython: language_level=3 - ''' + code) - except CompileError as exc: - assert code in [s.strip() for s in str(exc).splitlines()], str(exc) - else: - assert False, "Invalid Cython code '%s' failed to raise an exception" % code - - def test_valid_number_literals(self): - for literal in VALID_UNDERSCORE_LITERALS: - for i, expression in enumerate(['%s', '1 + %s', '%s + 1', '2 * %s', '%s * 2']): - code = 'x = ' + expression % literal - node = self.fragment(u'''\ - # cython: language_level=3 - ''' + code).root - assert node is not None - - literal_node = node.stats[0].rhs # StatListNode([SingleAssignmentNode('x', expr)]) - if i > 0: - # Add/MulNode() -> literal is first or second operand - literal_node = literal_node.operand2 if i % 2 else literal_node.operand1 - if 'j' in literal or 'J' in literal: - assert isinstance(literal_node, ExprNodes.ImagNode) - elif '.' in literal or 'e' in literal or 'E' in literal and not ('0x' in literal or '0X' in literal): - assert isinstance(literal_node, ExprNodes.FloatNode) - else: - assert isinstance(literal_node, ExprNodes.IntNode) - - -if __name__ == "__main__": - import unittest - unittest.main() +# mode: run +# tag: syntax + +""" +Uses TreeFragment to test invalid syntax. +""" + +from __future__ import absolute_import + +from ...TestUtils import CythonTest +from ..Errors import CompileError +from .. import ExprNodes + +# Copied from CPython's test_grammar.py +VALID_UNDERSCORE_LITERALS = [ + '0_0_0', + '4_2', + '1_0000_0000', + '0b1001_0100', + '0xffff_ffff', + '0o5_7_7', + '1_00_00.5', + '1_00_00.5j', + '1_00_00.5e5', + '1_00_00j', + '1_00_00e5_1', + '1e1_0', + '.1_4', + '.1_4e1', + '.1_4j', +] + +# Copied from CPython's test_grammar.py +INVALID_UNDERSCORE_LITERALS = [ + # Trailing underscores: + '0_', + '42_', + '1.4j_', + '0b1_', + '0xf_', + '0o5_', + # Underscores in the base selector: + '0_b0', + '0_xf', + '0_o5', + # Underscore right after the base selector: + '0b_0', + '0x_f', + '0o_5', + # Old-style octal, still disallowed: + #'0_7', + #'09_99', + # Special case with exponent: + '0 if 1_Else 1', + # Underscore right before a dot: + '1_.4', + '1_.4j', + # Underscore right after a dot: + '1._4', + '1._4j', + '._5', + # Underscore right after a sign: + '1.0e+_1', + # Multiple consecutive underscores: + '4_______2', + '0.1__4', + '0b1001__0100', + '0xffff__ffff', + '0o5__77', + '1e1__0', + # Underscore right before j: + '1.4_j', + '1.4e5_j', + # Underscore right before e: + '1_e1', + '1.4_e1', + # Underscore right after e: + '1e_1', + '1.4e_1', + # Whitespace in literals + '1_ 2', + '1 _2', + '1_2.2_ 1', + '1_2.2 _1', + '1_2e _1', + '1_2e2 _1', + '1_2e 2_1', +] + + +class TestGrammar(CythonTest): + + def test_invalid_number_literals(self): + for literal in INVALID_UNDERSCORE_LITERALS: + for expression in ['%s', '1 + %s', '%s + 1', '2 * %s', '%s * 2']: + code = 'x = ' + expression % literal + try: + self.fragment(u'''\ + # cython: language_level=3 + ''' + code) + except CompileError as exc: + assert code in [s.strip() for s in str(exc).splitlines()], str(exc) + else: + assert False, "Invalid Cython code '%s' failed to raise an exception" % code + + def test_valid_number_literals(self): + for literal in VALID_UNDERSCORE_LITERALS: + for i, expression in enumerate(['%s', '1 + %s', '%s + 1', '2 * %s', '%s * 2']): + code = 'x = ' + expression % literal + node = self.fragment(u'''\ + # cython: language_level=3 + ''' + code).root + assert node is not None + + literal_node = node.stats[0].rhs # StatListNode([SingleAssignmentNode('x', expr)]) + if i > 0: + # Add/MulNode() -> literal is first or second operand + literal_node = literal_node.operand2 if i % 2 else literal_node.operand1 + if 'j' in literal or 'J' in literal: + assert isinstance(literal_node, ExprNodes.ImagNode) + elif '.' in literal or 'e' in literal or 'E' in literal and not ('0x' in literal or '0X' in literal): + assert isinstance(literal_node, ExprNodes.FloatNode) + else: + assert isinstance(literal_node, ExprNodes.IntNode) + + +if __name__ == "__main__": + import unittest + unittest.main() diff --git a/contrib/tools/cython/Cython/Compiler/Tests/TestSignatureMatching.py b/contrib/tools/cython/Cython/Compiler/Tests/TestSignatureMatching.py index 4b0bef8175..166bb225b9 100644 --- a/contrib/tools/cython/Cython/Compiler/Tests/TestSignatureMatching.py +++ b/contrib/tools/cython/Cython/Compiler/Tests/TestSignatureMatching.py @@ -16,7 +16,7 @@ class SignatureMatcherTest(unittest.TestCase): Test the signature matching algorithm for overloaded signatures. """ def assertMatches(self, expected_type, arg_types, functions): - match = pt.best_match(arg_types, functions) + match = pt.best_match(arg_types, functions) if expected_type is not None: self.assertNotEqual(None, match) self.assertEqual(expected_type, match.type) diff --git a/contrib/tools/cython/Cython/Compiler/TreeFragment.py b/contrib/tools/cython/Cython/Compiler/TreeFragment.py index 5d2150f347..b85da8191a 100644 --- a/contrib/tools/cython/Cython/Compiler/TreeFragment.py +++ b/contrib/tools/cython/Cython/Compiler/TreeFragment.py @@ -9,7 +9,7 @@ Support for parsing strings into code trees. from __future__ import absolute_import import re -from io import StringIO +from io import StringIO from .Scanning import PyrexScanner, StringSourceDescriptor from .Symtab import ModuleScope @@ -17,7 +17,7 @@ from . import PyrexTypes from .Visitor import VisitorTransform from .Nodes import Node, StatListNode from .ExprNodes import NameNode -from .StringEncoding import _unicode +from .StringEncoding import _unicode from . import Parsing from . import Main from . import UtilNodes @@ -25,21 +25,21 @@ from . import UtilNodes class StringParseContext(Main.Context): def __init__(self, name, include_directories=None, compiler_directives=None, cpp=False): - if include_directories is None: - include_directories = [] - if compiler_directives is None: - compiler_directives = {} - # TODO: see if "language_level=3" also works for our internal code here. - Main.Context.__init__(self, include_directories, compiler_directives, cpp=cpp, language_level=2) + if include_directories is None: + include_directories = [] + if compiler_directives is None: + compiler_directives = {} + # TODO: see if "language_level=3" also works for our internal code here. + Main.Context.__init__(self, include_directories, compiler_directives, cpp=cpp, language_level=2) self.module_name = name - def find_module(self, module_name, relative_to=None, pos=None, need_pxd=1, absolute_fallback=True): + def find_module(self, module_name, relative_to=None, pos=None, need_pxd=1, absolute_fallback=True): if module_name not in (self.module_name, 'cython'): raise AssertionError("Not yet supporting any cimports/includes from string code snippets") - return ModuleScope(module_name, parent_module=None, context=self) + return ModuleScope(module_name, parent_module=None, context=self) -def parse_from_strings(name, code, pxds=None, level=None, initial_pos=None, +def parse_from_strings(name, code, pxds=None, level=None, initial_pos=None, context=None, allow_struct_enum_decorator=False): """ Utility method to parse a (unicode) string of code. This is mostly @@ -60,7 +60,7 @@ def parse_from_strings(name, code, pxds=None, level=None, initial_pos=None, # to use a unicode string so that code fragments don't have to bother # with encoding. This means that test code passed in should not have an # encoding header. - assert isinstance(code, _unicode), "unicode code snippets only please" + assert isinstance(code, _unicode), "unicode code snippets only please" encoding = "UTF-8" module_name = name @@ -68,7 +68,7 @@ def parse_from_strings(name, code, pxds=None, level=None, initial_pos=None, initial_pos = (name, 1, 0) code_source = StringSourceDescriptor(name, code) - scope = context.find_module(module_name, pos=initial_pos, need_pxd=False) + scope = context.find_module(module_name, pos=initial_pos, need_pxd=False) buf = StringIO(code) @@ -86,7 +86,7 @@ def parse_from_strings(name, code, pxds=None, level=None, initial_pos=None, tree.scope = scope return tree - + class TreeCopier(VisitorTransform): def visit_Node(self, node): if node is None: @@ -96,7 +96,7 @@ class TreeCopier(VisitorTransform): self.visitchildren(c) return c - + class ApplyPositionAndCopy(TreeCopier): def __init__(self, pos): super(ApplyPositionAndCopy, self).__init__() @@ -107,7 +107,7 @@ class ApplyPositionAndCopy(TreeCopier): copy.pos = self.pos return copy - + class TemplateTransform(VisitorTransform): """ Makes a copy of a template tree while doing substitutions. @@ -197,16 +197,16 @@ class TemplateTransform(VisitorTransform): else: return self.visit_Node(node) - + def copy_code_tree(node): return TreeCopier()(node) - -_match_indent = re.compile(u"^ *").match - - + +_match_indent = re.compile(u"^ *").match + + def strip_common_indent(lines): - """Strips empty lines and common indentation from the list of strings given in lines""" + """Strips empty lines and common indentation from the list of strings given in lines""" # TODO: Facilitate textwrap.indent instead lines = [x for x in lines if x.strip() != u""] if lines: @@ -214,24 +214,24 @@ def strip_common_indent(lines): lines = [x[minindent:] for x in lines] return lines - + class TreeFragment(object): - def __init__(self, code, name=None, pxds=None, temps=None, pipeline=None, level=None, initial_pos=None): - if pxds is None: - pxds = {} - if temps is None: - temps = [] - if pipeline is None: - pipeline = [] - if not name: - name = "(tree fragment)" - - if isinstance(code, _unicode): + def __init__(self, code, name=None, pxds=None, temps=None, pipeline=None, level=None, initial_pos=None): + if pxds is None: + pxds = {} + if temps is None: + temps = [] + if pipeline is None: + pipeline = [] + if not name: + name = "(tree fragment)" + + if isinstance(code, _unicode): def fmt(x): return u"\n".join(strip_common_indent(x.split(u"\n"))) fmt_code = fmt(code) fmt_pxds = {} - for key, value in pxds.items(): + for key, value in pxds.items(): fmt_pxds[key] = fmt(value) mod = t = parse_from_strings(name, fmt_code, fmt_pxds, level=level, initial_pos=initial_pos) if level is None: @@ -244,8 +244,8 @@ class TreeFragment(object): t = transform(t) self.root = t elif isinstance(code, Node): - if pxds: - raise NotImplementedError() + if pxds: + raise NotImplementedError() self.root = code else: raise ValueError("Unrecognized code format (accepts unicode and Node)") @@ -254,16 +254,16 @@ class TreeFragment(object): def copy(self): return copy_code_tree(self.root) - def substitute(self, nodes=None, temps=None, pos = None): - if nodes is None: - nodes = {} - if temps is None: - temps = [] + def substitute(self, nodes=None, temps=None, pos = None): + if nodes is None: + nodes = {} + if temps is None: + temps = [] return TemplateTransform()(self.root, substitutions = nodes, temps = self.temps + temps, pos = pos) - + class SetPosTransform(VisitorTransform): def __init__(self, pos): super(SetPosTransform, self).__init__() diff --git a/contrib/tools/cython/Cython/Compiler/TreePath.py b/contrib/tools/cython/Cython/Compiler/TreePath.py index 20db8aae26..8585905557 100644 --- a/contrib/tools/cython/Cython/Compiler/TreePath.py +++ b/contrib/tools/cython/Cython/Compiler/TreePath.py @@ -18,14 +18,14 @@ else: _unicode = unicode path_tokenizer = re.compile( - r"(" - r"'[^']*'|\"[^\"]*\"|" - r"//?|" - r"\(\)|" - r"==?|" - r"[/.*\[\]()@])|" - r"([^/\[\]()@=\s]+)|" - r"\s+" + r"(" + r"'[^']*'|\"[^\"]*\"|" + r"//?|" + r"\(\)|" + r"==?|" + r"[/.*\[\]()@])|" + r"([^/\[\]()@=\s]+)|" + r"\s+" ).findall def iterchildren(node, attr_name): diff --git a/contrib/tools/cython/Cython/Compiler/TypeInference.py b/contrib/tools/cython/Cython/Compiler/TypeInference.py index 1edda5bbfa..c7ffee7d24 100644 --- a/contrib/tools/cython/Cython/Compiler/TypeInference.py +++ b/contrib/tools/cython/Cython/Compiler/TypeInference.py @@ -9,19 +9,19 @@ from .. import Utils from .PyrexTypes import py_object_type, unspecified_type from .Visitor import CythonTransform, EnvTransform -try: - reduce -except NameError: - from functools import reduce +try: + reduce +except NameError: + from functools import reduce + - class TypedExprNode(ExprNodes.ExprNode): # Used for declaring assignments of a specified type without a known entry. - subexprs = [] + subexprs = [] + + def __init__(self, type, pos=None): + super(TypedExprNode, self).__init__(pos, type=type) - def __init__(self, type, pos=None): - super(TypedExprNode, self).__init__(pos, type=type) - object_expr = TypedExprNode(py_object_type) @@ -68,12 +68,12 @@ class MarkParallelAssignments(EnvTransform): parallel_node.assigned_nodes.append(lhs) elif isinstance(lhs, ExprNodes.SequenceNode): - for i, arg in enumerate(lhs.args): - if not rhs or arg.is_starred: - item_node = None - else: - item_node = rhs.inferable_item_node(i) - self.mark_assignment(arg, item_node) + for i, arg in enumerate(lhs.args): + if not rhs or arg.is_starred: + item_node = None + else: + item_node = rhs.inferable_item_node(i) + self.mark_assignment(arg, item_node) else: # Could use this info to infer cdef class attributes... pass @@ -191,10 +191,10 @@ class MarkParallelAssignments(EnvTransform): # use fake expressions with the right result type if node.star_arg: self.mark_assignment( - node.star_arg, TypedExprNode(Builtin.tuple_type, node.pos)) + node.star_arg, TypedExprNode(Builtin.tuple_type, node.pos)) if node.starstar_arg: self.mark_assignment( - node.starstar_arg, TypedExprNode(Builtin.dict_type, node.pos)) + node.starstar_arg, TypedExprNode(Builtin.dict_type, node.pos)) EnvTransform.visit_FuncDefNode(self, node) return node @@ -404,7 +404,7 @@ class SimpleAssignmentTypeInferer(object): else: entry = node.entry node_type = spanning_type( - types, entry.might_overflow, entry.pos, scope) + types, entry.might_overflow, entry.pos, scope) node.inferred_type = node_type def infer_name_node_type_partial(node): @@ -413,7 +413,7 @@ class SimpleAssignmentTypeInferer(object): if not types: return entry = node.entry - return spanning_type(types, entry.might_overflow, entry.pos, scope) + return spanning_type(types, entry.might_overflow, entry.pos, scope) def inferred_types(entry): has_none = False @@ -488,7 +488,7 @@ class SimpleAssignmentTypeInferer(object): types = inferred_types(entry) if types and all(types): entry_type = spanning_type( - types, entry.might_overflow, entry.pos, scope) + types, entry.might_overflow, entry.pos, scope) inferred.add(entry) self.set_entry_type(entry, entry_type) @@ -498,7 +498,7 @@ class SimpleAssignmentTypeInferer(object): for assmt in entry.cf_assignments: assmt.infer_type() types = inferred_types(entry) - new_type = spanning_type(types, entry.might_overflow, entry.pos, scope) + new_type = spanning_type(types, entry.might_overflow, entry.pos, scope) if new_type != entry.type: self.set_entry_type(entry, new_type) dirty = True @@ -530,22 +530,22 @@ def find_spanning_type(type1, type2): return PyrexTypes.c_double_type return result_type -def simply_type(result_type, pos): +def simply_type(result_type, pos): if result_type.is_reference: result_type = result_type.ref_base_type if result_type.is_const: result_type = result_type.const_base_type if result_type.is_cpp_class: result_type.check_nullary_constructor(pos) - if result_type.is_array: - result_type = PyrexTypes.c_ptr_type(result_type.base_type) + if result_type.is_array: + result_type = PyrexTypes.c_ptr_type(result_type.base_type) return result_type -def aggressive_spanning_type(types, might_overflow, pos, scope): - return simply_type(reduce(find_spanning_type, types), pos) - -def safe_spanning_type(types, might_overflow, pos, scope): - result_type = simply_type(reduce(find_spanning_type, types), pos) +def aggressive_spanning_type(types, might_overflow, pos, scope): + return simply_type(reduce(find_spanning_type, types), pos) + +def safe_spanning_type(types, might_overflow, pos, scope): + result_type = simply_type(reduce(find_spanning_type, types), pos) if result_type.is_pyobject: # In theory, any specific Python type is always safe to # infer. However, inferring str can cause some existing code @@ -581,9 +581,9 @@ def safe_spanning_type(types, might_overflow, pos, scope): # to make sure everything is supported. elif (result_type.is_int or result_type.is_enum) and not might_overflow: return result_type - elif (not result_type.can_coerce_to_pyobject(scope) - and not result_type.is_error): - return result_type + elif (not result_type.can_coerce_to_pyobject(scope) + and not result_type.is_error): + return result_type return py_object_type diff --git a/contrib/tools/cython/Cython/Compiler/TypeSlots.py b/contrib/tools/cython/Cython/Compiler/TypeSlots.py index 34e31df0af..0b4ff67042 100644 --- a/contrib/tools/cython/Cython/Compiler/TypeSlots.py +++ b/contrib/tools/cython/Cython/Compiler/TypeSlots.py @@ -7,7 +7,7 @@ from __future__ import absolute_import from . import Naming from . import PyrexTypes -from .Errors import error +from .Errors import error invisible = ['__cinit__', '__dealloc__', '__richcmp__', '__nonzero__', '__bool__'] @@ -73,7 +73,7 @@ class Signature(object): } type_to_format_map = dict( - (type_, format_) for format_, type_ in format_map.items()) + (type_, format_) for format_, type_ in format_map.items()) error_value_map = { 'O': "NULL", @@ -101,12 +101,12 @@ class Signature(object): self.exception_check = ret_format != 'r' and self.error_value is not None self.is_staticmethod = False - def __repr__(self): - return '<Signature[%s(%s%s)]>' % ( - self.ret_format, - ', '.join(self.fixed_arg_format), - '*' if self.has_generic_args else '') - + def __repr__(self): + return '<Signature[%s(%s%s)]>' % ( + self.ret_format, + ', '.join(self.fixed_arg_format), + '*' if self.has_generic_args else '') + def num_fixed_args(self): return len(self.fixed_arg_format) @@ -135,7 +135,7 @@ class Signature(object): def function_type(self, self_arg_override=None): # Construct a C function type descriptor for this signature args = [] - for i in range(self.num_fixed_args()): + for i in range(self.num_fixed_args()): if self_arg_override is not None and self.is_self_arg(i): assert isinstance(self_arg_override, PyrexTypes.CFuncTypeArg) args.append(self_arg_override) @@ -202,10 +202,10 @@ class SlotDescriptor(object): return guard def generate(self, scope, code): - preprocessor_guard = self.preprocessor_guard_code() - if preprocessor_guard: - code.putln(preprocessor_guard) - + preprocessor_guard = self.preprocessor_guard_code() + if preprocessor_guard: + code.putln(preprocessor_guard) + end_pypy_guard = False if self.is_initialised_dynamically: value = "0" @@ -229,12 +229,12 @@ class SlotDescriptor(object): code.putln("%s, /*%s*/" % (inherited_value, self.slot_name)) code.putln("#else") end_pypy_guard = True - + code.putln("%s, /*%s*/" % (value, self.slot_name)) - - if end_pypy_guard: - code.putln("#endif") - + + if end_pypy_guard: + code.putln("#endif") + if self.py3 == '<RESERVED>': code.putln("#else") code.putln("0, /*reserved*/") @@ -370,7 +370,7 @@ class ConstructorSlot(InternalMethodSlot): and scope.parent_type.base_type and not scope.has_pyobject_attrs and not scope.has_memoryview_attrs - and not scope.has_cpp_class_attrs + and not scope.has_cpp_class_attrs and not (entry and entry.is_special)): # if the type does not have object attributes, it can # delegate GC methods to its parent - iff the parent @@ -439,12 +439,12 @@ class DocStringSlot(SlotDescriptor): # Descriptor for the docstring slot. def slot_code(self, scope): - doc = scope.doc - if doc is None: + doc = scope.doc + if doc is None: return "0" - if doc.is_unicode: - doc = doc.as_utf8_string() - return doc.as_c_string_literal() + if doc.is_unicode: + doc = doc.as_utf8_string() + return doc.as_c_string_literal() class SuiteSlot(SlotDescriptor): @@ -452,8 +452,8 @@ class SuiteSlot(SlotDescriptor): # # sub_slots [SlotDescriptor] - def __init__(self, sub_slots, slot_type, slot_name, ifdef=None): - SlotDescriptor.__init__(self, slot_name, ifdef=ifdef) + def __init__(self, sub_slots, slot_type, slot_name, ifdef=None): + SlotDescriptor.__init__(self, slot_name, ifdef=ifdef) self.sub_slots = sub_slots self.slot_type = slot_type substructures.append(self) @@ -475,8 +475,8 @@ class SuiteSlot(SlotDescriptor): def generate_substructure(self, scope, code): if not self.is_empty(scope): code.putln("") - if self.ifdef: - code.putln("#if %s" % self.ifdef) + if self.ifdef: + code.putln("#if %s" % self.ifdef) code.putln( "static %s %s = {" % ( self.slot_type, @@ -484,8 +484,8 @@ class SuiteSlot(SlotDescriptor): for slot in self.sub_slots: slot.generate(scope, code) code.putln("};") - if self.ifdef: - code.putln("#endif") + if self.ifdef: + code.putln("#endif") substructures = [] # List of all SuiteSlot instances @@ -531,27 +531,27 @@ class BaseClassSlot(SlotDescriptor): base_type.typeptr_cname)) -class DictOffsetSlot(SlotDescriptor): - # Slot descriptor for a class' dict offset, for dynamic attributes. - - def slot_code(self, scope): +class DictOffsetSlot(SlotDescriptor): + # Slot descriptor for a class' dict offset, for dynamic attributes. + + def slot_code(self, scope): dict_entry = scope.lookup_here("__dict__") if not scope.is_closure_class_scope else None - if dict_entry and dict_entry.is_variable: - if getattr(dict_entry.type, 'cname', None) != 'PyDict_Type': - error(dict_entry.pos, "__dict__ slot must be of type 'dict'") - return "0" - type = scope.parent_type - if type.typedef_flag: - objstruct = type.objstruct_cname - else: - objstruct = "struct %s" % type.objstruct_cname - return ("offsetof(%s, %s)" % ( - objstruct, - dict_entry.cname)) - else: - return "0" - - + if dict_entry and dict_entry.is_variable: + if getattr(dict_entry.type, 'cname', None) != 'PyDict_Type': + error(dict_entry.pos, "__dict__ slot must be of type 'dict'") + return "0" + type = scope.parent_type + if type.typedef_flag: + objstruct = type.objstruct_cname + else: + objstruct = "struct %s" % type.objstruct_cname + return ("offsetof(%s, %s)" % ( + objstruct, + dict_entry.cname)) + else: + return "0" + + # The following dictionary maps __xxx__ method names to slot descriptors. method_name_to_slot = {} @@ -726,12 +726,12 @@ property_accessor_signatures = { #------------------------------------------------------------------------------------------ PyNumberMethods_Py3_GUARD = "PY_MAJOR_VERSION < 3 || (CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x03050000)" - + PyNumberMethods = ( MethodSlot(binaryfunc, "nb_add", "__add__"), MethodSlot(binaryfunc, "nb_subtract", "__sub__"), MethodSlot(binaryfunc, "nb_multiply", "__mul__"), - MethodSlot(binaryfunc, "nb_divide", "__div__", ifdef = PyNumberMethods_Py3_GUARD), + MethodSlot(binaryfunc, "nb_divide", "__div__", ifdef = PyNumberMethods_Py3_GUARD), MethodSlot(binaryfunc, "nb_remainder", "__mod__"), MethodSlot(binaryfunc, "nb_divmod", "__divmod__"), MethodSlot(ternaryfunc, "nb_power", "__pow__"), @@ -745,18 +745,18 @@ PyNumberMethods = ( MethodSlot(binaryfunc, "nb_and", "__and__"), MethodSlot(binaryfunc, "nb_xor", "__xor__"), MethodSlot(binaryfunc, "nb_or", "__or__"), - EmptySlot("nb_coerce", ifdef = PyNumberMethods_Py3_GUARD), + EmptySlot("nb_coerce", ifdef = PyNumberMethods_Py3_GUARD), MethodSlot(unaryfunc, "nb_int", "__int__", fallback="__long__"), MethodSlot(unaryfunc, "nb_long", "__long__", fallback="__int__", py3 = "<RESERVED>"), MethodSlot(unaryfunc, "nb_float", "__float__"), - MethodSlot(unaryfunc, "nb_oct", "__oct__", ifdef = PyNumberMethods_Py3_GUARD), - MethodSlot(unaryfunc, "nb_hex", "__hex__", ifdef = PyNumberMethods_Py3_GUARD), + MethodSlot(unaryfunc, "nb_oct", "__oct__", ifdef = PyNumberMethods_Py3_GUARD), + MethodSlot(unaryfunc, "nb_hex", "__hex__", ifdef = PyNumberMethods_Py3_GUARD), # Added in release 2.0 MethodSlot(ibinaryfunc, "nb_inplace_add", "__iadd__"), MethodSlot(ibinaryfunc, "nb_inplace_subtract", "__isub__"), MethodSlot(ibinaryfunc, "nb_inplace_multiply", "__imul__"), - MethodSlot(ibinaryfunc, "nb_inplace_divide", "__idiv__", ifdef = PyNumberMethods_Py3_GUARD), + MethodSlot(ibinaryfunc, "nb_inplace_divide", "__idiv__", ifdef = PyNumberMethods_Py3_GUARD), MethodSlot(ibinaryfunc, "nb_inplace_remainder", "__imod__"), MethodSlot(ibinaryfunc, "nb_inplace_power", "__ipow__"), # actually ternaryfunc!!! MethodSlot(ibinaryfunc, "nb_inplace_lshift", "__ilshift__"), @@ -809,13 +809,13 @@ PyBufferProcs = ( MethodSlot(releasebufferproc, "bf_releasebuffer", "__releasebuffer__") ) -PyAsyncMethods = ( - MethodSlot(unaryfunc, "am_await", "__await__"), - MethodSlot(unaryfunc, "am_aiter", "__aiter__"), - MethodSlot(unaryfunc, "am_anext", "__anext__"), +PyAsyncMethods = ( + MethodSlot(unaryfunc, "am_await", "__await__"), + MethodSlot(unaryfunc, "am_aiter", "__aiter__"), + MethodSlot(unaryfunc, "am_anext", "__anext__"), EmptySlot("am_send", ifdef="PY_VERSION_HEX >= 0x030A00A3"), -) - +) + #------------------------------------------------------------------------------------------ # # The main slot table. This table contains descriptors for all the @@ -826,15 +826,15 @@ PyAsyncMethods = ( slot_table = ( ConstructorSlot("tp_dealloc", '__dealloc__'), - EmptySlot("tp_print", ifdef="PY_VERSION_HEX < 0x030800b4"), - EmptySlot("tp_vectorcall_offset", ifdef="PY_VERSION_HEX >= 0x030800b4"), + EmptySlot("tp_print", ifdef="PY_VERSION_HEX < 0x030800b4"), + EmptySlot("tp_vectorcall_offset", ifdef="PY_VERSION_HEX >= 0x030800b4"), EmptySlot("tp_getattr"), EmptySlot("tp_setattr"), - - # tp_compare (Py2) / tp_reserved (Py3<3.5) / tp_as_async (Py3.5+) is always used as tp_as_async in Py3 - MethodSlot(cmpfunc, "tp_compare", "__cmp__", ifdef="PY_MAJOR_VERSION < 3"), - SuiteSlot(PyAsyncMethods, "__Pyx_PyAsyncMethodsStruct", "tp_as_async", ifdef="PY_MAJOR_VERSION >= 3"), - + + # tp_compare (Py2) / tp_reserved (Py3<3.5) / tp_as_async (Py3.5+) is always used as tp_as_async in Py3 + MethodSlot(cmpfunc, "tp_compare", "__cmp__", ifdef="PY_MAJOR_VERSION < 3"), + SuiteSlot(PyAsyncMethods, "__Pyx_PyAsyncMethodsStruct", "tp_as_async", ifdef="PY_MAJOR_VERSION >= 3"), + MethodSlot(reprfunc, "tp_repr", "__repr__"), SuiteSlot(PyNumberMethods, "PyNumberMethods", "tp_as_number"), @@ -873,7 +873,7 @@ slot_table = ( SyntheticSlot("tp_descr_get", ["__get__"], "0"), SyntheticSlot("tp_descr_set", ["__set__", "__delete__"], "0"), - DictOffsetSlot("tp_dictoffset"), + DictOffsetSlot("tp_dictoffset"), MethodSlot(initproc, "tp_init", "__init__"), EmptySlot("tp_alloc"), #FixedSlot("tp_alloc", "PyType_GenericAlloc"), diff --git a/contrib/tools/cython/Cython/Compiler/UtilNodes.py b/contrib/tools/cython/Cython/Compiler/UtilNodes.py index 376fb602e1..c41748ace0 100644 --- a/contrib/tools/cython/Cython/Compiler/UtilNodes.py +++ b/contrib/tools/cython/Cython/Compiler/UtilNodes.py @@ -51,15 +51,15 @@ class TempRefNode(AtomicExprNode): def generate_result_code(self, code): pass - def generate_assignment_code(self, rhs, code, overloaded_assignment=False): + def generate_assignment_code(self, rhs, code, overloaded_assignment=False): if self.type.is_pyobject: rhs.make_owned_reference(code) # TODO: analyse control flow to see if this is necessary code.put_xdecref(self.result(), self.ctype()) - code.putln('%s = %s;' % ( - self.result(), - rhs.result() if overloaded_assignment else rhs.result_as(self.ctype()), - )) + code.putln('%s = %s;' % ( + self.result(), + rhs.result() if overloaded_assignment else rhs.result_as(self.ctype()), + )) rhs.generate_post_assignment_code(code) rhs.free_temps(code) @@ -142,15 +142,15 @@ class ResultRefNode(AtomicExprNode): else: return () - def update_expression(self, expression): - self.expression = expression - if hasattr(expression, "type"): - self.type = expression.type - + def update_expression(self, expression): + self.expression = expression + if hasattr(expression, "type"): + self.type = expression.type + def analyse_types(self, env): if self.expression is not None: - if not self.expression.type: - self.expression = self.expression.analyse_types(env) + if not self.expression.type: + self.expression = self.expression.analyse_types(env) self.type = self.expression.type return self @@ -197,15 +197,15 @@ class ResultRefNode(AtomicExprNode): def generate_disposal_code(self, code): pass - def generate_assignment_code(self, rhs, code, overloaded_assignment=False): + def generate_assignment_code(self, rhs, code, overloaded_assignment=False): if self.type.is_pyobject: rhs.make_owned_reference(code) if not self.lhs_of_first_assignment: code.put_decref(self.result(), self.ctype()) - code.putln('%s = %s;' % ( - self.result(), - rhs.result() if overloaded_assignment else rhs.result_as(self.ctype()), - )) + code.putln('%s = %s;' % ( + self.result(), + rhs.result() if overloaded_assignment else rhs.result_as(self.ctype()), + )) rhs.generate_post_assignment_code(code) rhs.free_temps(code) @@ -250,7 +250,7 @@ class LetNodeMixin: code.put_decref_clear(self.temp, self.temp_type) code.funcstate.release_temp(self.temp) - + class EvalWithTempExprNode(ExprNodes.ExprNode, LetNodeMixin): # A wrapper around a subexpression that moves an expression into a # temp variable and provides it to the subexpression. @@ -275,7 +275,7 @@ class EvalWithTempExprNode(ExprNodes.ExprNode, LetNodeMixin): def analyse_types(self, env): self.temp_expression = self.temp_expression.analyse_types(env) - self.lazy_temp.update_expression(self.temp_expression) # overwrite in case it changed + self.lazy_temp.update_expression(self.temp_expression) # overwrite in case it changed self.subexpression = self.subexpression.analyse_types(env) self.type = self.subexpression.type return self @@ -291,10 +291,10 @@ class EvalWithTempExprNode(ExprNodes.ExprNode, LetNodeMixin): self.subexpression.generate_evaluation_code(code) self.teardown_temp_expr(code) - + LetRefNode = ResultRefNode - + class LetNode(Nodes.StatNode, LetNodeMixin): # Implements a local temporary variable scope. Imagine this # syntax being present: diff --git a/contrib/tools/cython/Cython/Compiler/UtilityCode.py b/contrib/tools/cython/Cython/Compiler/UtilityCode.py index 91daffe65f..98e9ab5bfb 100644 --- a/contrib/tools/cython/Cython/Compiler/UtilityCode.py +++ b/contrib/tools/cython/Cython/Compiler/UtilityCode.py @@ -16,7 +16,7 @@ class NonManglingModuleScope(Symtab.ModuleScope): def add_imported_entry(self, name, entry, pos): entry.used = True - return super(NonManglingModuleScope, self).add_imported_entry(name, entry, pos) + return super(NonManglingModuleScope, self).add_imported_entry(name, entry, pos) def mangle(self, prefix, name=None): if name: @@ -28,13 +28,13 @@ class NonManglingModuleScope(Symtab.ModuleScope): else: return Symtab.ModuleScope.mangle(self, prefix) - + class CythonUtilityCodeContext(StringParseContext): scope = None - def find_module(self, module_name, relative_to=None, pos=None, need_pxd=True, absolute_fallback=True): - if relative_to: - raise AssertionError("Relative imports not supported in utility code.") + def find_module(self, module_name, relative_to=None, pos=None, need_pxd=True, absolute_fallback=True): + if relative_to: + raise AssertionError("Relative imports not supported in utility code.") if module_name != self.module_name: if module_name not in self.modules: raise AssertionError("Only the cython cimport is supported.") @@ -42,7 +42,7 @@ class CythonUtilityCodeContext(StringParseContext): return self.modules[module_name] if self.scope is None: - self.scope = NonManglingModuleScope( + self.scope = NonManglingModuleScope( self.prefix, module_name, parent_module=None, context=self, cpp=self.cpp) return self.scope @@ -68,8 +68,8 @@ class CythonUtilityCode(Code.UtilityCodeBase): is_cython_utility = True def __init__(self, impl, name="__pyxutil", prefix="", requires=None, - file=None, from_scope=None, context=None, compiler_directives=None, - outer_module_scope=None): + file=None, from_scope=None, context=None, compiler_directives=None, + outer_module_scope=None): # 1) We need to delay the parsing/processing, so that all modules can be # imported without import loops # 2) The same utility code object can be used for multiple source files; @@ -90,25 +90,25 @@ class CythonUtilityCode(Code.UtilityCodeBase): self.prefix = prefix self.requires = requires or [] self.from_scope = from_scope - self.outer_module_scope = outer_module_scope - self.compiler_directives = compiler_directives + self.outer_module_scope = outer_module_scope + self.compiler_directives = compiler_directives self.context_types = context_types - def __eq__(self, other): - if isinstance(other, CythonUtilityCode): - return self._equality_params() == other._equality_params() - else: - return False - - def _equality_params(self): - outer_scope = self.outer_module_scope - while isinstance(outer_scope, NonManglingModuleScope): - outer_scope = outer_scope.outer_scope - return self.impl, outer_scope, self.compiler_directives - - def __hash__(self): - return hash(self.impl) - + def __eq__(self, other): + if isinstance(other, CythonUtilityCode): + return self._equality_params() == other._equality_params() + else: + return False + + def _equality_params(self): + outer_scope = self.outer_module_scope + while isinstance(outer_scope, NonManglingModuleScope): + outer_scope = outer_scope.outer_scope + return self.impl, outer_scope, self.compiler_directives + + def __hash__(self): + return hash(self.impl) + def get_tree(self, entries_only=False, cython_scope=None): from .AnalysedTreeTransforms import AutoTestDictTransform # The AutoTestDictTransform creates the statement "__test__ = {}", @@ -117,14 +117,14 @@ class CythonUtilityCode(Code.UtilityCodeBase): excludes = [AutoTestDictTransform] from . import Pipeline, ParseTreeTransforms - context = CythonUtilityCodeContext( + context = CythonUtilityCodeContext( self.name, compiler_directives=self.compiler_directives, cpp=cython_scope.is_cpp() if cython_scope else False) context.prefix = self.prefix context.cython_scope = cython_scope #context = StringParseContext(self.name) - tree = parse_from_strings( - self.name, self.impl, context=context, allow_struct_enum_decorator=True) + tree = parse_from_strings( + self.name, self.impl, context=context, allow_struct_enum_decorator=True) pipeline = Pipeline.create_pipeline(context, 'pyx', exclude_classes=excludes) if entries_only: @@ -143,33 +143,33 @@ class CythonUtilityCode(Code.UtilityCodeBase): pipeline = Pipeline.insert_into_pipeline(pipeline, transform, before=before) - def merge_scope(scope): - def merge_scope_transform(module_node): - module_node.scope.merge_in(scope) + def merge_scope(scope): + def merge_scope_transform(module_node): + module_node.scope.merge_in(scope) return module_node - return merge_scope_transform - - if self.from_scope: - pipeline = Pipeline.insert_into_pipeline( - pipeline, merge_scope(self.from_scope), - before=ParseTreeTransforms.AnalyseDeclarationsTransform) - - for dep in self.requires: - if isinstance(dep, CythonUtilityCode) and hasattr(dep, 'tree') and not cython_scope: - pipeline = Pipeline.insert_into_pipeline( - pipeline, merge_scope(dep.tree.scope), - before=ParseTreeTransforms.AnalyseDeclarationsTransform) - - if self.outer_module_scope: - # inject outer module between utility code module and builtin module - def scope_transform(module_node): - module_node.scope.outer_scope = self.outer_module_scope - return module_node - - pipeline = Pipeline.insert_into_pipeline( - pipeline, scope_transform, - before=ParseTreeTransforms.AnalyseDeclarationsTransform) - + return merge_scope_transform + + if self.from_scope: + pipeline = Pipeline.insert_into_pipeline( + pipeline, merge_scope(self.from_scope), + before=ParseTreeTransforms.AnalyseDeclarationsTransform) + + for dep in self.requires: + if isinstance(dep, CythonUtilityCode) and hasattr(dep, 'tree') and not cython_scope: + pipeline = Pipeline.insert_into_pipeline( + pipeline, merge_scope(dep.tree.scope), + before=ParseTreeTransforms.AnalyseDeclarationsTransform) + + if self.outer_module_scope: + # inject outer module between utility code module and builtin module + def scope_transform(module_node): + module_node.scope.outer_scope = self.outer_module_scope + return module_node + + pipeline = Pipeline.insert_into_pipeline( + pipeline, scope_transform, + before=ParseTreeTransforms.AnalyseDeclarationsTransform) + if self.context_types: # inject types into module scope def scope_transform(module_node): @@ -184,7 +184,7 @@ class CythonUtilityCode(Code.UtilityCodeBase): (err, tree) = Pipeline.run_pipeline(pipeline, tree, printtree=False) assert not err, err - self.tree = tree + self.tree = tree return tree def put_code(self, output): @@ -213,12 +213,12 @@ class CythonUtilityCode(Code.UtilityCodeBase): entries.pop('__builtins__') entries.pop('__doc__') - for entry in entries.values(): + for entry in entries.values(): entry.utility_code_definition = self entry.used = used original_scope = tree.scope - dest_scope.merge_in(original_scope, merge_unused=True, whitelist=whitelist) + dest_scope.merge_in(original_scope, merge_unused=True, whitelist=whitelist) tree.scope = dest_scope for dep in self.requires: @@ -227,7 +227,7 @@ class CythonUtilityCode(Code.UtilityCodeBase): return original_scope - + def declare_declarations_in_scope(declaration_string, env, private_type=True, *args, **kwargs): """ diff --git a/contrib/tools/cython/Cython/Compiler/Visitor.pxd b/contrib/tools/cython/Cython/Compiler/Visitor.pxd index 36fe5b1885..d5d5692aa7 100644 --- a/contrib/tools/cython/Cython/Compiler/Visitor.pxd +++ b/contrib/tools/cython/Cython/Compiler/Visitor.pxd @@ -12,13 +12,13 @@ cdef class TreeVisitor: cdef _visitchild(self, child, parent, attrname, idx) cdef dict _visitchildren(self, parent, attrs) cpdef visitchildren(self, parent, attrs=*) - cdef _raise_compiler_error(self, child, e) + cdef _raise_compiler_error(self, child, e) cdef class VisitorTransform(TreeVisitor): - cdef dict _process_children(self, parent, attrs=*) - cpdef visitchildren(self, parent, attrs=*, exclude=*) - cdef list _flatten_list(self, list orig_list) - cdef list _select_attrs(self, attrs, exclude) + cdef dict _process_children(self, parent, attrs=*) + cpdef visitchildren(self, parent, attrs=*, exclude=*) + cdef list _flatten_list(self, list orig_list) + cdef list _select_attrs(self, attrs, exclude) cdef class CythonTransform(VisitorTransform): cdef public context diff --git a/contrib/tools/cython/Cython/Compiler/Visitor.py b/contrib/tools/cython/Cython/Compiler/Visitor.py index ad5525fe01..a35d13e1d0 100644 --- a/contrib/tools/cython/Cython/Compiler/Visitor.py +++ b/contrib/tools/cython/Cython/Compiler/Visitor.py @@ -1,14 +1,14 @@ # cython: infer_types=True -# cython: language_level=3 -# cython: auto_pickle=False +# cython: language_level=3 +# cython: auto_pickle=False # # Tree visitor and transform framework # -from __future__ import absolute_import, print_function +from __future__ import absolute_import, print_function -import sys +import sys import inspect from . import TypeSlots @@ -17,19 +17,19 @@ from . import Nodes from . import ExprNodes from . import Errors from . import DebugFlags -from . import Future +from . import Future import cython -cython.declare(_PRINTABLE=tuple) - -if sys.version_info[0] >= 3: - _PRINTABLE = (bytes, str, int, float) -else: - _PRINTABLE = (str, unicode, long, int, float) - - +cython.declare(_PRINTABLE=tuple) + +if sys.version_info[0] >= 3: + _PRINTABLE = (bytes, str, int, float) +else: + _PRINTABLE = (str, unicode, long, int, float) + + class TreeVisitor(object): """ Base class for writing visitors for a Cython tree, contains utilities for @@ -59,9 +59,9 @@ class TreeVisitor(object): >>> tree = SampleNode(0, SampleNode(1), [SampleNode(2), SampleNode(3)]) >>> class MyVisitor(TreeVisitor): ... def visit_SampleNode(self, node): - ... print("in %s %s" % (node.value, self.access_path)) + ... print("in %s %s" % (node.value, self.access_path)) ... self.visitchildren(node) - ... print("out %s" % node.value) + ... print("out %s" % node.value) ... >>> MyVisitor().visit(tree) in 0 [] @@ -78,9 +78,9 @@ class TreeVisitor(object): self.dispatch_table = {} self.access_path = [] - def dump_node(self, node): - ignored = list(node.child_attrs or []) + [ - u'child_attrs', u'pos', u'gil_message', u'cpp_message', u'subexprs'] + def dump_node(self, node): + ignored = list(node.child_attrs or []) + [ + u'child_attrs', u'pos', u'gil_message', u'cpp_message', u'subexprs'] values = [] pos = getattr(node, 'pos', None) if pos: @@ -93,7 +93,7 @@ class TreeVisitor(object): for attr in attribute_names: if attr in ignored: continue - if attr.startswith('_') or attr.endswith('_'): + if attr.startswith('_') or attr.endswith('_'): continue try: value = getattr(node, attr) @@ -103,12 +103,12 @@ class TreeVisitor(object): continue elif isinstance(value, list): value = u'[...]/%d' % len(value) - elif not isinstance(value, _PRINTABLE): + elif not isinstance(value, _PRINTABLE): continue else: value = repr(value) values.append(u'%s = %s' % (attr, value)) - return u'%s(%s)' % (node.__class__.__name__, u',\n '.join(values)) + return u'%s(%s)' % (node.__class__.__name__, u',\n '.join(values)) def _find_node_path(self, stacktrace): import os.path @@ -159,11 +159,11 @@ class TreeVisitor(object): handler_method = getattr(self, pattern % mro_cls.__name__, None) if handler_method is not None: return handler_method - print(type(self), cls) + print(type(self), cls) if self.access_path: - print(self.access_path) - print(self.access_path[-1][0].pos) - print(self.access_path[-1][0].__dict__) + print(self.access_path) + print(self.access_path[-1][0].pos) + print(self.access_path[-1][0].__dict__) raise RuntimeError("Visitor %r does not accept object: %s" % (self, obj)) def visit(self, obj): @@ -182,7 +182,7 @@ class TreeVisitor(object): raise except Errors.AbortError: raise - except Exception as e: + except Exception as e: if DebugFlags.debug_no_exception_intercept: raise self._raise_compiler_error(obj, e) @@ -244,46 +244,46 @@ class VisitorTransform(TreeVisitor): was not, an exception will be raised. (Typically you want to ensure that you are within a StatListNode or similar before doing this.) """ - def visitchildren(self, parent, attrs=None, exclude=None): - # generic def entry point for calls from Python subclasses - if exclude is not None: - attrs = self._select_attrs(parent.child_attrs if attrs is None else attrs, exclude) - return self._process_children(parent, attrs) - - @cython.final - def _select_attrs(self, attrs, exclude): - return [name for name in attrs if name not in exclude] - - @cython.final - def _process_children(self, parent, attrs=None): - # fast cdef entry point for calls from Cython subclasses + def visitchildren(self, parent, attrs=None, exclude=None): + # generic def entry point for calls from Python subclasses + if exclude is not None: + attrs = self._select_attrs(parent.child_attrs if attrs is None else attrs, exclude) + return self._process_children(parent, attrs) + + @cython.final + def _select_attrs(self, attrs, exclude): + return [name for name in attrs if name not in exclude] + + @cython.final + def _process_children(self, parent, attrs=None): + # fast cdef entry point for calls from Cython subclasses result = self._visitchildren(parent, attrs) - for attr, newnode in result.items(): - if type(newnode) is list: - newnode = self._flatten_list(newnode) - setattr(parent, attr, newnode) + for attr, newnode in result.items(): + if type(newnode) is list: + newnode = self._flatten_list(newnode) + setattr(parent, attr, newnode) return result - @cython.final - def _flatten_list(self, orig_list): - # Flatten the list one level and remove any None - newlist = [] - for x in orig_list: - if x is not None: - if type(x) is list: - newlist.extend(x) - else: - newlist.append(x) - return newlist - + @cython.final + def _flatten_list(self, orig_list): + # Flatten the list one level and remove any None + newlist = [] + for x in orig_list: + if x is not None: + if type(x) is list: + newlist.extend(x) + else: + newlist.append(x) + return newlist + def recurse_to_children(self, node): - self._process_children(node) + self._process_children(node) return node def __call__(self, root): return self._visit(root) - + class CythonTransform(VisitorTransform): """ Certain common conventions and utilities for Cython transforms. @@ -304,15 +304,15 @@ class CythonTransform(VisitorTransform): def visit_CompilerDirectivesNode(self, node): old = self.current_directives self.current_directives = node.directives - self._process_children(node) + self._process_children(node) self.current_directives = old return node def visit_Node(self, node): - self._process_children(node) + self._process_children(node) return node - + class ScopeTrackingTransform(CythonTransform): # Keeps track of type of scopes #scope_type: can be either of 'module', 'function', 'cclass', 'pyclass', 'struct' @@ -321,14 +321,14 @@ class ScopeTrackingTransform(CythonTransform): def visit_ModuleNode(self, node): self.scope_type = 'module' self.scope_node = node - self._process_children(node) + self._process_children(node) return node def visit_scope(self, node, scope_type): prev = self.scope_type, self.scope_node self.scope_type = scope_type self.scope_node = node - self._process_children(node) + self._process_children(node) self.scope_type, self.scope_node = prev return node @@ -371,45 +371,45 @@ class EnvTransform(CythonTransform): def visit_FuncDefNode(self, node): self.enter_scope(node, node.local_scope) - self._process_children(node) + self._process_children(node) self.exit_scope() return node def visit_GeneratorBodyDefNode(self, node): - self._process_children(node) + self._process_children(node) return node def visit_ClassDefNode(self, node): self.enter_scope(node, node.scope) - self._process_children(node) + self._process_children(node) self.exit_scope() return node def visit_CStructOrUnionDefNode(self, node): self.enter_scope(node, node.scope) - self._process_children(node) + self._process_children(node) self.exit_scope() return node def visit_ScopedExprNode(self, node): if node.expr_scope: self.enter_scope(node, node.expr_scope) - self._process_children(node) + self._process_children(node) self.exit_scope() else: - self._process_children(node) + self._process_children(node) return node def visit_CArgDeclNode(self, node): # default arguments are evaluated in the outer scope if node.default: - attrs = [attr for attr in node.child_attrs if attr != 'default'] - self._process_children(node, attrs) + attrs = [attr for attr in node.child_attrs if attr != 'default'] + self._process_children(node, attrs) self.enter_scope(node, self.current_env().outer_scope) self.visitchildren(node, ('default',)) self.exit_scope() else: - self._process_children(node) + self._process_children(node) return node @@ -430,7 +430,7 @@ class NodeRefCleanupMixin(object): def visit_CloneNode(self, node): arg = node.arg if arg not in self._replacements: - self.visitchildren(arg) + self.visitchildren(arg) node.arg = self._replacements.get(arg, arg) return node @@ -457,7 +457,7 @@ find_special_method_for_binary_operator = { '>': '__gt__', '+': '__add__', '&': '__and__', - '/': '__div__', + '/': '__div__', '//': '__floordiv__', '<<': '__lshift__', '%': '__mod__', @@ -494,7 +494,7 @@ class MethodDispatcherTransform(EnvTransform): """ # only visit call nodes and Python operations def visit_GeneralCallNode(self, node): - self._process_children(node) + self._process_children(node) function = node.function if not function.type.is_pyobject: return node @@ -509,7 +509,7 @@ class MethodDispatcherTransform(EnvTransform): return self._dispatch_to_handler(node, function, args, keyword_args) def visit_SimpleCallNode(self, node): - self._process_children(node) + self._process_children(node) function = node.function if function.type.is_pyobject: arg_tuple = node.arg_tuple @@ -523,7 +523,7 @@ class MethodDispatcherTransform(EnvTransform): def visit_PrimaryCmpNode(self, node): if node.cascade: # not currently handled below - self._process_children(node) + self._process_children(node) return node return self._visit_binop_node(node) @@ -531,16 +531,16 @@ class MethodDispatcherTransform(EnvTransform): return self._visit_binop_node(node) def _visit_binop_node(self, node): - self._process_children(node) + self._process_children(node) # FIXME: could special case 'not_in' special_method_name = find_special_method_for_binary_operator(node.operator) if special_method_name: operand1, operand2 = node.operand1, node.operand2 if special_method_name == '__contains__': operand1, operand2 = operand2, operand1 - elif special_method_name == '__div__': - if Future.division in self.current_env().global_scope().context.future_directives: - special_method_name = '__truediv__' + elif special_method_name == '__div__': + if Future.division in self.current_env().global_scope().context.future_directives: + special_method_name = '__truediv__' obj_type = operand1.type if obj_type.is_builtin_type: type_name = obj_type.name @@ -552,7 +552,7 @@ class MethodDispatcherTransform(EnvTransform): return node def visit_UnopNode(self, node): - self._process_children(node) + self._process_children(node) special_method_name = find_special_method_for_unary_operator(node.operator) if special_method_name: operand = node.operand @@ -624,19 +624,19 @@ class MethodDispatcherTransform(EnvTransform): return function_handler(node, function, arg_list, kwargs) else: return function_handler(node, function, arg_list) - elif function.is_attribute: + elif function.is_attribute: attr_name = function.attribute - if function.type.is_pyobject: - self_arg = function.obj - elif node.self and function.entry: - entry = function.entry.as_variable - if not entry or not entry.is_builtin: - return node - # C implementation of a Python builtin method - see if we find further matches - self_arg = node.self - arg_list = arg_list[1:] # drop CloneNode of self argument - else: - return node + if function.type.is_pyobject: + self_arg = function.obj + elif node.self and function.entry: + entry = function.entry.as_variable + if not entry or not entry.is_builtin: + return node + # C implementation of a Python builtin method - see if we find further matches + self_arg = node.self + arg_list = arg_list[1:] # drop CloneNode of self argument + else: + return node obj_type = self_arg.type is_unbound_method = False if obj_type.is_builtin_type: @@ -673,12 +673,12 @@ class MethodDispatcherTransform(EnvTransform): if self_arg is not None: arg_list = [self_arg] + list(arg_list) if kwargs: - result = method_handler( + result = method_handler( node, function, arg_list, is_unbound_method, kwargs) else: - result = method_handler( + result = method_handler( node, function, arg_list, is_unbound_method) - return result + return result def _handle_function(self, node, function_name, function, arg_list, kwargs): """Fallback handler""" @@ -699,15 +699,15 @@ class RecursiveNodeReplacer(VisitorTransform): super(RecursiveNodeReplacer, self).__init__() self.orig_node, self.new_node = orig_node, new_node - def visit_CloneNode(self, node): - if node is self.orig_node: - return self.new_node - if node.arg is self.orig_node: - node.arg = self.new_node - return node - + def visit_CloneNode(self, node): + if node is self.orig_node: + return self.new_node + if node.arg is self.orig_node: + node.arg = self.new_node + return node + def visit_Node(self, node): - self._process_children(node) + self._process_children(node) if node is self.orig_node: return self.new_node else: @@ -752,22 +752,22 @@ def replace_node(ptr, value): else: getattr(parent, attrname)[listidx] = value - + class PrintTree(TreeVisitor): """Prints a representation of the tree to standard output. Subclass and override repr_of to provide more information about nodes. """ - def __init__(self, start=None, end=None): + def __init__(self, start=None, end=None): TreeVisitor.__init__(self) self._indent = "" - if start is not None or end is not None: - self._line_range = (start or 0, end or 2**30) - else: - self._line_range = None + if start is not None or end is not None: + self._line_range = (start or 0, end or 2**30) + else: + self._line_range = None def indent(self): self._indent += " " - + def unindent(self): self._indent = self._indent[:-2] @@ -781,37 +781,37 @@ class PrintTree(TreeVisitor): # under the parent-node, not displaying the list itself in # the hierarchy. def visit_Node(self, node): - self._print_node(node) + self._print_node(node) self.indent() self.visitchildren(node) self.unindent() return node - def visit_CloneNode(self, node): - self._print_node(node) - self.indent() - line = node.pos[1] - if self._line_range is None or self._line_range[0] <= line <= self._line_range[1]: - print("%s- %s: %s" % (self._indent, 'arg', self.repr_of(node.arg))) - self.indent() - self.visitchildren(node.arg) - self.unindent() - self.unindent() - return node - - def _print_node(self, node): - line = node.pos[1] - if self._line_range is None or self._line_range[0] <= line <= self._line_range[1]: - if len(self.access_path) == 0: - name = "(root)" - else: - parent, attr, idx = self.access_path[-1] - if idx is not None: - name = "%s[%d]" % (attr, idx) - else: - name = attr - print("%s- %s: %s" % (self._indent, name, self.repr_of(node))) - + def visit_CloneNode(self, node): + self._print_node(node) + self.indent() + line = node.pos[1] + if self._line_range is None or self._line_range[0] <= line <= self._line_range[1]: + print("%s- %s: %s" % (self._indent, 'arg', self.repr_of(node.arg))) + self.indent() + self.visitchildren(node.arg) + self.unindent() + self.unindent() + return node + + def _print_node(self, node): + line = node.pos[1] + if self._line_range is None or self._line_range[0] <= line <= self._line_range[1]: + if len(self.access_path) == 0: + name = "(root)" + else: + parent, attr, idx = self.access_path[-1] + if idx is not None: + name = "%s[%d]" % (attr, idx) + else: + name = attr + print("%s- %s: %s" % (self._indent, name, self.repr_of(node))) + def repr_of(self, node): if node is None: return "(none)" |