pax_global_header 0000666 0000000 0000000 00000000064 11446142532 0014514 g ustar 00root root 0000000 0000000 52 comment=29e61a09e5fe337d35bf6cc54e548ca0205e4058
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/ 0000775 0000000 0000000 00000000000 11446142532 0017744 5 ustar 00root root 0000000 0000000 cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/.hgignore 0000664 0000000 0000000 00000000156 11446142532 0021551 0 ustar 00root root 0000000 0000000 syntax: glob
*.pyc
*.swp
Cython/Compiler/Lexicon.pickle
BUILD/
build/
.coverage
*~
*.orig
*.rej
*.dep
tags
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/.hgtags 0000664 0000000 0000000 00000002442 11446142532 0021224 0 ustar 00root root 0000000 0000000 966abe58538dfbdaccd53bd970d4998c78ea522e 0.9.6.14
67ee5a34bfc662e4e3cf989c2c8bf78a412ae8f4 0.9.8rc1
16a746d969e2654112fc0dc081690b891c496977 Version-0.9.8
a09347d7b470290076b983aef98707921445a038 0.9.8.1
82084a7b654e2a133ab64ceb47e03d6e7a204990 0.9.9.2.beta
a89b05b78236a27a654f3004bdffc7b8a56311a7 0.10
ef9d2c680684d0df7d81f529cda29e9e1741f575 cython-0.10.1
92baafe0edf3cea00deb7ce1e31e337bb485af1a 0.10.2
cdf889c30e7a7053de20bae3a578dad09ebcbdf5 0.10.3
59c67af0674bd93c5fd8958e08c76a9dab9aae37 sage-cythonizes
a4abf0156540db4d3ebaa95712b65811c43c5acb 0.11-beta
838a6b7cae62e01dc0ce663cccab1f93f649fdbd 0.11.rc
4497f635d5fdbd38ebb841be4869fbfa2bbfdbb6 0.11.1.alpha
7bc36a0f81723117a19f92ffde1676a0884fef65 0.11.1.beta
6454db601984145f38e28d34176fca8a3a22329c 0.11.1
af6f1bed8cd40a2edefb57d3eacbc9274a8788b4 0.11.2.rc1
15ad532e2127840ae09dfbe46ccc80ac8c562f99 0.11.2
eb00d00a73c13b6aa8b440fe07cd7acb52a060e8 0.11.3.rc0
7c695fe49fd6912f52d995fe512d66baacf90ee6 0.11.3
4208042ceeae634f5c0999b8ab75f69faf46b6db 0.12.alpha0
e77827f09af67560aa82a18feab778f71ca0a9d3 0.12.rc0
fae19937e4945c59a5d9d62c63f1c3b09046c3a3 0.12
e90c522631ae06f2170a751fb256cdea0e50fb21 0.12.1
5ac2eaefcdc9c3a7a9c29a0bb8c3e4c6c016c64c 0.13.beta0
14957f635a379c97d9966097276313e43491ed96 0.13.beta1
32c957267b3ba3140fba4d1947fa98484d5e956b 0.13
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/COPYING.txt 0000664 0000000 0000000 00000000661 11446142532 0021620 0 ustar 00root root 0000000 0000000 The original Pyrex code as of 2006-04 is licensed under the following
license: "Copyright stuff: Pyrex is free of restrictions. You may use,
redistribute, modify and distribute modified versions."
------------------
Cython, which derives from Pyrex, is licensed under the Python
Software Foundation License. More precisely, all modifications
made to go from Pyrex to Cython are so licensed.
See LICENSE.txt for more details.
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/ 0000775 0000000 0000000 00000000000 11446142532 0021210 5 ustar 00root root 0000000 0000000 cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/CodeWriter.py 0000664 0000000 0000000 00000022405 11446142532 0023634 0 ustar 00root root 0000000 0000000 from Cython.Compiler.Visitor import TreeVisitor
from Cython.Compiler.Nodes import *
from Cython.Compiler.ExprNodes import *
"""
Serializes a Cython code tree to Cython code. This is primarily useful for
debugging and testing purposes.
The output is in a strict format, no whitespace or comments from the input
is preserved (and it could not be as it is not present in the code tree).
"""
class LinesResult(object):
def __init__(self):
self.lines = []
self.s = u""
def put(self, s):
self.s += s
def newline(self):
self.lines.append(self.s)
self.s = u""
def putline(self, s):
self.put(s)
self.newline()
class CodeWriter(TreeVisitor):
indent_string = u" "
def __init__(self, result = None):
super(CodeWriter, self).__init__()
if result is None:
result = LinesResult()
self.result = result
self.numindents = 0
self.tempnames = {}
self.tempblockindex = 0
def write(self, tree):
self.visit(tree)
def indent(self):
self.numindents += 1
def dedent(self):
self.numindents -= 1
def startline(self, s = u""):
self.result.put(self.indent_string * self.numindents + s)
def put(self, s):
self.result.put(s)
def endline(self, s = u""):
self.result.putline(s)
def line(self, s):
self.startline(s)
self.endline()
def comma_separated_list(self, items, output_rhs=False):
if len(items) > 0:
for item in items[:-1]:
self.visit(item)
if output_rhs and item.default is not None:
self.put(u" = ")
self.visit(item.default)
self.put(u", ")
self.visit(items[-1])
def visit_Node(self, node):
raise AssertionError("Node not handled by serializer: %r" % node)
def visit_ModuleNode(self, node):
self.visitchildren(node)
def visit_StatListNode(self, node):
self.visitchildren(node)
def visit_FuncDefNode(self, node):
self.startline(u"def %s(" % node.name)
self.comma_separated_list(node.args)
self.endline(u"):")
self.indent()
self.visit(node.body)
self.dedent()
def visit_CArgDeclNode(self, node):
if node.base_type.name is not None:
self.visit(node.base_type)
self.put(u" ")
self.visit(node.declarator)
if node.default is not None:
self.put(u" = ")
self.visit(node.default)
def visit_CNameDeclaratorNode(self, node):
self.put(node.name)
def visit_CSimpleBaseTypeNode(self, node):
# See Parsing.p_sign_and_longness
if node.is_basic_c_type:
self.put(("unsigned ", "", "signed ")[node.signed])
if node.longness < 0:
self.put("short " * -node.longness)
elif node.longness > 0:
self.put("long " * node.longness)
self.put(node.name)
def visit_SingleAssignmentNode(self, node):
self.startline()
self.visit(node.lhs)
self.put(u" = ")
self.visit(node.rhs)
self.endline()
def visit_CascadedAssignmentNode(self, node):
self.startline()
for lhs in node.lhs_list:
self.visit(lhs)
self.put(u" = ")
self.visit(node.rhs)
self.endline()
def visit_NameNode(self, node):
self.put(node.name)
def visit_IntNode(self, node):
self.put(node.value)
# FIXME: represent string nodes correctly
def visit_StringNode(self, node):
value = node.value
if value.encoding is not None:
value = value.encode(value.encoding)
self.put(repr(value))
def visit_IfStatNode(self, node):
# The IfClauseNode is handled directly without a seperate match
# for clariy.
self.startline(u"if ")
self.visit(node.if_clauses[0].condition)
self.endline(":")
self.indent()
self.visit(node.if_clauses[0].body)
self.dedent()
for clause in node.if_clauses[1:]:
self.startline("elif ")
self.visit(clause.condition)
self.endline(":")
self.indent()
self.visit(clause.body)
self.dedent()
if node.else_clause is not None:
self.line("else:")
self.indent()
self.visit(node.else_clause)
self.dedent()
def visit_PassStatNode(self, node):
self.startline(u"pass")
self.endline()
def visit_PrintStatNode(self, node):
self.startline(u"print ")
self.comma_separated_list(node.arg_tuple.args)
if not node.append_newline:
self.put(u",")
self.endline()
def visit_BinopNode(self, node):
self.visit(node.operand1)
self.put(u" %s " % node.operator)
self.visit(node.operand2)
def visit_CVarDefNode(self, node):
self.startline(u"cdef ")
self.visit(node.base_type)
self.put(u" ")
self.comma_separated_list(node.declarators, output_rhs=True)
self.endline()
def visit_ForInStatNode(self, node):
self.startline(u"for ")
self.visit(node.target)
self.put(u" in ")
self.visit(node.iterator.sequence)
self.endline(u":")
self.indent()
self.visit(node.body)
self.dedent()
if node.else_clause is not None:
self.line(u"else:")
self.indent()
self.visit(node.else_clause)
self.dedent()
def visit_SequenceNode(self, node):
self.comma_separated_list(node.args) # Might need to discover whether we need () around tuples...hmm...
def visit_SimpleCallNode(self, node):
self.visit(node.function)
self.put(u"(")
self.comma_separated_list(node.args)
self.put(")")
def visit_GeneralCallNode(self, node):
self.visit(node.function)
self.put(u"(")
posarg = node.positional_args
if isinstance(posarg, AsTupleNode):
self.visit(posarg.arg)
else:
self.comma_separated_list(posarg)
if node.keyword_args is not None or node.starstar_arg is not None:
raise Exception("Not implemented yet")
self.put(u")")
def visit_ExprStatNode(self, node):
self.startline()
self.visit(node.expr)
self.endline()
def visit_InPlaceAssignmentNode(self, node):
self.startline()
self.visit(node.lhs)
self.put(u" %s= " % node.operator)
self.visit(node.rhs)
self.endline()
def visit_WithStatNode(self, node):
self.startline()
self.put(u"with ")
self.visit(node.manager)
if node.target is not None:
self.put(u" as ")
self.visit(node.target)
self.endline(u":")
self.indent()
self.visit(node.body)
self.dedent()
def visit_AttributeNode(self, node):
self.visit(node.obj)
self.put(u".%s" % node.attribute)
def visit_BoolNode(self, node):
self.put(str(node.value))
def visit_TryFinallyStatNode(self, node):
self.line(u"try:")
self.indent()
self.visit(node.body)
self.dedent()
self.line(u"finally:")
self.indent()
self.visit(node.finally_clause)
self.dedent()
def visit_TryExceptStatNode(self, node):
self.line(u"try:")
self.indent()
self.visit(node.body)
self.dedent()
for x in node.except_clauses:
self.visit(x)
if node.else_clause is not None:
self.visit(node.else_clause)
def visit_ExceptClauseNode(self, node):
self.startline(u"except")
if node.pattern is not None:
self.put(u" ")
self.visit(node.pattern)
if node.target is not None:
self.put(u", ")
self.visit(node.target)
self.endline(":")
self.indent()
self.visit(node.body)
self.dedent()
def visit_ReturnStatNode(self, node):
self.startline("return ")
self.visit(node.value)
self.endline()
def visit_DecoratorNode(self, node):
self.startline("@")
self.visit(node.decorator)
self.endline()
def visit_ReraiseStatNode(self, node):
self.line("raise")
def visit_NoneNode(self, node):
self.put(u"None")
def visit_ImportNode(self, node):
self.put(u"(import %s)" % node.module_name.value)
def visit_NotNode(self, node):
self.put(u"(not ")
self.visit(node.operand)
self.put(u")")
def visit_TempsBlockNode(self, node):
"""
Temporaries are output like $1_1', where the first number is
an index of the TempsBlockNode and the second number is an index
of the temporary which that block allocates.
"""
idx = 0
for handle in node.temps:
self.tempnames[handle] = "$%d_%d" % (self.tempblockindex, idx)
idx += 1
self.tempblockindex += 1
self.visit(node.body)
def visit_TempRefNode(self, node):
self.put(self.tempnames[node.handle])
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/ 0000775 0000000 0000000 00000000000 11446142532 0022762 5 ustar 00root root 0000000 0000000 cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/AnalysedTreeTransforms.py 0000664 0000000 0000000 00000011072 11446142532 0027774 0 ustar 00root root 0000000 0000000 from Cython.Compiler.Visitor import VisitorTransform, ScopeTrackingTransform, TreeVisitor
from Nodes import StatListNode, SingleAssignmentNode, CFuncDefNode
from ExprNodes import DictNode, DictItemNode, NameNode, UnicodeNode, NoneNode, \
ExprNode, AttributeNode, ModuleRefNode, DocstringRefNode
from PyrexTypes import py_object_type
from Builtin import dict_type
from StringEncoding import EncodedString
import Naming
import Symtab
class AutoTestDictTransform(ScopeTrackingTransform):
# Handles autotestdict directive
blacklist = ['__cinit__', '__dealloc__', '__richcmp__',
'__nonzero__', '__bool__',
'__len__', '__contains__']
def visit_ModuleNode(self, node):
if node.is_pxd:
return node
self.scope_type = 'module'
self.scope_node = node
if self.current_directives['autotestdict']:
assert isinstance(node.body, StatListNode)
# First see if __test__ is already created
if u'__test__' in node.scope.entries:
# Do nothing
return node
pos = node.pos
self.tests = []
self.testspos = node.pos
test_dict_entry = node.scope.declare_var(EncodedString(u'__test__'),
py_object_type,
pos,
visibility='public')
create_test_dict_assignment = SingleAssignmentNode(pos,
lhs=NameNode(pos, name=EncodedString(u'__test__'),
entry=test_dict_entry),
rhs=DictNode(pos, key_value_pairs=self.tests))
self.visitchildren(node)
node.body.stats.append(create_test_dict_assignment)
return node
def add_test(self, testpos, name, func_ref_node):
# func_ref_node must evaluate to the function object containing
# the docstring, BUT it should not be the function itself (which
# would lead to a new *definition* of the function)
pos = self.testspos
keystr = u'%s (line %d)' % (name, testpos[1])
key = UnicodeNode(pos, value=EncodedString(keystr))
value = DocstringRefNode(pos, func_ref_node)
self.tests.append(DictItemNode(pos, key=key, value=value))
def visit_FuncDefNode(self, node):
if node.doc:
if isinstance(node, CFuncDefNode) and not node.py_func:
# skip non-cpdef cdef functions
return node
pos = self.testspos
if self.scope_type == 'module':
parent = ModuleRefNode(pos)
name = node.entry.name
elif self.scope_type in ('pyclass', 'cclass'):
if isinstance(node, CFuncDefNode):
name = node.py_func.name
else:
name = node.name
if self.scope_type == 'cclass' and name in self.blacklist:
return node
mod = ModuleRefNode(pos)
if self.scope_type == 'pyclass':
clsname = self.scope_node.name
else:
clsname = self.scope_node.class_name
parent = AttributeNode(pos, obj=mod,
attribute=clsname,
type=py_object_type,
is_py_attr=True,
is_temp=True)
if isinstance(node.entry.scope, Symtab.PropertyScope):
new_node = AttributeNode(pos, obj=parent,
attribute=node.entry.scope.name,
type=py_object_type,
is_py_attr=True,
is_temp=True)
parent = new_node
name = "%s.%s.%s" % (clsname, node.entry.scope.name,
node.entry.name)
else:
name = "%s.%s" % (clsname, node.entry.name)
else:
assert False
getfunc = AttributeNode(pos, obj=parent,
attribute=node.entry.name,
type=py_object_type,
is_py_attr=True,
is_temp=True)
self.add_test(node.pos, name, getfunc)
return node
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Annotate.py 0000664 0000000 0000000 00000016164 11446142532 0025115 0 ustar 00root root 0000000 0000000 # Note: Work in progress
import os
import re
import time
import codecs
from StringIO import StringIO
import Version
from Code import CCodeWriter
from Cython import Utils
# need one-characters subsitutions (for now) so offsets aren't off
special_chars = [(u'<', u'\xF0', u'<'),
(u'>', u'\xF1', u'>'),
(u'&', u'\xF2', u'&')]
line_pos_comment = re.compile(r'/\*.*?<<<<<<<<<<<<<<.*?\*/\n*', re.DOTALL)
class AnnotationCCodeWriter(CCodeWriter):
def __init__(self, create_from=None, buffer=None, copy_formatting=True):
CCodeWriter.__init__(self, create_from, buffer, copy_formatting=True)
if create_from is None:
self.annotation_buffer = StringIO()
self.annotations = []
self.last_pos = None
self.code = {}
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.last_pos = create_from.last_pos
def create_new(self, create_from, buffer, copy_formatting):
return AnnotationCCodeWriter(create_from, buffer, copy_formatting)
def write(self, s):
CCodeWriter.write(self, s)
self.annotation_buffer.write(s)
def mark_pos(self, pos):
if pos is not None:
CCodeWriter.mark_pos(self, pos)
if self.last_pos:
pos_code = self.code.setdefault(self.last_pos[0].get_description(),{})
code = pos_code.get(self.last_pos[1], "")
pos_code[self.last_pos[1]] = code + self.annotation_buffer.getvalue()
self.annotation_buffer = StringIO()
self.last_pos = pos
def annotate(self, pos, item):
self.annotations.append((pos, item))
def save_annotation(self, source_filename, target_filename):
self.mark_pos(None)
f = Utils.open_source_file(source_filename)
lines = f.readlines()
for k in range(len(lines)):
line = lines[k]
for c, cc, html in special_chars:
line = line.replace(c, cc)
lines[k] = line
f.close()
all = []
if False:
for pos, item in self.annotations:
if pos[0].filename == source_filename:
start = item.start()
size, end = item.end()
if size:
all.append((pos, start))
all.append(((source_filename, pos[1], pos[2]+size), end))
else:
all.append((pos, start+end))
all.sort()
all.reverse()
for pos, item in all:
_, line_no, col = pos
line_no -= 1
col += 1
line = lines[line_no]
lines[line_no] = line[:col] + item + line[col:]
html_filename = os.path.splitext(target_filename)[0] + ".html"
f = codecs.open(html_filename, "w", encoding="UTF-8")
f.write(u'\n')
f.write(u"""
""")
f.write(u'\n')
f.write(u'Generated by Cython %s on %s\n' % (Version.version, time.asctime()))
c_file = Utils.decode_filename(os.path.basename(target_filename))
f.write(u'
Raw output: %s \n' % (c_file, c_file))
k = 0
py_c_api = re.compile(u'(Py[A-Z][a-z]+_[A-Z][a-z][A-Za-z_]+)\(')
py_marco_api = re.compile(u'(Py[A-Z][a-z]+_[A-Z][A-Z_]+)\(')
pyx_c_api = re.compile(u'(__Pyx_[A-Z][a-z_][A-Za-z_]+)\(')
pyx_macro_api = re.compile(u'(__Pyx_[A-Z][A-Z_]+)\(')
error_goto = re.compile(ur'((; *if .*)? \{__pyx_filename = .*goto __pyx_L\w+;\})')
refnanny = re.compile(u'(__Pyx_X?(GOT|GIVE)REF|__Pyx_RefNanny[A-Za-z]+)')
code_source_file = self.code[source_filename]
for line in lines:
k += 1
try:
code = code_source_file[k]
except KeyError:
code = ''
code = code.replace('<', '<
')
code, py_c_api_calls = py_c_api.subn(ur"\1 (", code)
code, pyx_c_api_calls = pyx_c_api.subn(ur"\1 (", code)
code, py_macro_api_calls = py_marco_api.subn(ur"\1 (", code)
code, pyx_macro_api_calls = pyx_macro_api.subn(ur"\1 (", code)
code, refnanny_calls = refnanny.subn(ur"\1 ", code)
code, error_goto_calls = error_goto.subn(ur"\1 ", code)
code = code.replace(u";", u";")
score = 5*py_c_api_calls + 2*pyx_c_api_calls + py_macro_api_calls + pyx_macro_api_calls - refnanny_calls
color = u"FFFF%02x" % int(255/(1+score/10.0))
f.write(u"" % (color, k))
f.write(u" %d: " % k)
for c, cc, html in special_chars:
line = line.replace(cc, html)
f.write(line.rstrip())
f.write(u' \n')
code = re.sub(line_pos_comment, '', code) # inline annotations are redundant
f.write(u"%s " % (k, color, code))
f.write(u'\n')
f.close()
# TODO: make this cleaner
def escape(raw_string):
raw_string = raw_string.replace(u"\'", ur"")
raw_string = raw_string.replace(u'\"', ur'"')
raw_string = raw_string.replace(u'\n', ur' \n')
raw_string = raw_string.replace(u'\t', ur'\t')
return raw_string
class AnnotationItem(object):
def __init__(self, style, text, tag="", size=0):
self.style = style
self.text = text
self.tag = tag
self.size = size
def start(self):
return u"%s" % (self.style, self.text, self.tag)
def end(self):
return self.size, u" "
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/AutoDocTransforms.py 0000664 0000000 0000000 00000014626 11446142532 0026762 0 ustar 00root root 0000000 0000000 from Cython.Compiler.Visitor import CythonTransform
from Cython.Compiler.Nodes import DefNode, CFuncDefNode
from Cython.Compiler.Errors import CompileError
from Cython.Compiler.StringEncoding import EncodedString
from Cython.Compiler import Options
from Cython.Compiler import PyrexTypes, ExprNodes
class EmbedSignature(CythonTransform):
def __init__(self, context):
super(EmbedSignature, self).__init__(context)
self.denv = None # XXX
self.class_name = None
self.class_node = None
def _fmt_arg_defv(self, arg):
default_val = arg.default
if not default_val:
return None
try:
denv = self.denv # XXX
ctval = default_val.compile_time_value(self.denv)
repr_val = repr(ctval)
if isinstance(default_val, ExprNodes.UnicodeNode):
if repr_val[:1] != 'u':
return u'u%s' % repr_val
elif isinstance(default_val, ExprNodes.BytesNode):
if repr_val[:1] != 'b':
return u'b%s' % repr_val
elif isinstance(default_val, ExprNodes.StringNode):
if repr_val[:1] in 'ub':
return repr_val[1:]
return repr_val
except Exception:
try:
return default_val.name # XXX
except AttributeError:
return '??>'
def _fmt_arg(self, arg):
if arg.type is PyrexTypes.py_object_type or arg.is_self_arg:
doc = arg.name
else:
doc = arg.type.declaration_code(arg.name, for_display=1)
if arg.default:
arg_defv = self._fmt_arg_defv(arg)
if arg_defv:
doc = doc + ('=%s' % arg_defv)
return doc
def _fmt_arglist(self, args,
npargs=0, pargs=None,
nkargs=0, kargs=None,
hide_self=False):
arglist = []
for arg in args:
if not hide_self or not arg.entry.is_self_arg:
arg_doc = self._fmt_arg(arg)
arglist.append(arg_doc)
if pargs:
arglist.insert(npargs, '*%s' % pargs.name)
elif nkargs:
arglist.insert(npargs, '*')
if kargs:
arglist.append('**%s' % kargs.name)
return arglist
def _fmt_ret_type(self, ret):
if ret is PyrexTypes.py_object_type:
return None
else:
return ret.declaration_code("", for_display=1)
def _fmt_signature(self, cls_name, func_name, args,
npargs=0, pargs=None,
nkargs=0, kargs=None,
return_type=None, hide_self=False):
arglist = self._fmt_arglist(args,
npargs, pargs,
nkargs, kargs,
hide_self=hide_self)
arglist_doc = ', '.join(arglist)
func_doc = '%s(%s)' % (func_name, arglist_doc)
if cls_name:
func_doc = '%s.%s' % (cls_name, func_doc)
if return_type:
ret_doc = self._fmt_ret_type(return_type)
if ret_doc:
func_doc = '%s -> %s' % (func_doc, ret_doc)
return func_doc
def _embed_signature(self, signature, node_doc):
if node_doc:
return "%s\n%s" % (signature, node_doc)
else:
return signature
def __call__(self, node):
if not Options.docstrings:
return node
else:
return super(EmbedSignature, self).__call__(node)
def visit_ClassDefNode(self, node):
oldname = self.class_name
oldclass = self.class_node
self.class_node = node
try:
# PyClassDefNode
self.class_name = node.name
except AttributeError:
# CClassDefNode
self.class_name = node.class_name
self.visitchildren(node)
self.class_name = oldname
self.class_node = oldclass
return node
def visit_DefNode(self, node):
if not self.current_directives['embedsignature']:
return node
is_constructor = False
hide_self = False
if node.entry.is_special:
is_constructor = self.class_node and node.name == '__init__'
if not is_constructor:
return node
class_name, func_name = None, self.class_name
hide_self = True
else:
class_name, func_name = self.class_name, node.name
nkargs = getattr(node, 'num_kwonly_args', 0)
npargs = len(node.args) - nkargs
signature = self._fmt_signature(
class_name, func_name, node.args,
npargs, node.star_arg,
nkargs, node.starstar_arg,
return_type=None, hide_self=hide_self)
if signature:
if is_constructor:
doc_holder = self.class_node.entry.type.scope
else:
doc_holder = node.entry
if doc_holder.doc is not None:
old_doc = doc_holder.doc
elif not is_constructor and getattr(node, 'py_func', None) is not None:
old_doc = node.py_func.entry.doc
else:
old_doc = None
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)
return node
def visit_CFuncDefNode(self, node):
if not self.current_directives['embedsignature']:
return node
if not node.overridable: # not cpdef FOO(...):
return node
signature = self._fmt_signature(
self.class_name, node.declarator.base.name,
node.declarator.args,
return_type=node.return_type)
if signature:
if node.entry.doc is not None:
old_doc = node.entry.doc
elif getattr(node, 'py_func', None) is not None:
old_doc = node.py_func.entry.doc
else:
old_doc = None
new_doc = self._embed_signature(signature, old_doc)
node.entry.doc = EncodedString(new_doc)
if hasattr(node, 'py_func') and node.py_func is not None:
node.py_func.entry.doc = EncodedString(new_doc)
return node
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Buffer.py 0000664 0000000 0000000 00000123061 11446142532 0024550 0 ustar 00root root 0000000 0000000 from Visitor import VisitorTransform, CythonTransform
from ModuleNode import ModuleNode
from Nodes import *
from ExprNodes import *
from StringEncoding import EncodedString
from Errors import CompileError
from Code import UtilityCode
import Interpreter
import PyrexTypes
try:
set
except NameError:
from sets import Set as set
import textwrap
def dedent(text, reindent=0):
text = textwrap.dedent(text)
if reindent > 0:
indent = " " * reindent
text = '\n'.join([indent + x for x in text.split('\n')])
return text
class IntroduceBufferAuxiliaryVars(CythonTransform):
#
# Entry point
#
buffers_exists = False
def __call__(self, node):
assert isinstance(node, ModuleNode)
self.max_ndim = 0
result = super(IntroduceBufferAuxiliaryVars, self).__call__(node)
if self.buffers_exists:
use_py2_buffer_functions(node.scope)
use_empty_bufstruct_code(node.scope, self.max_ndim)
return result
#
# Basic operations for transforms
#
def handle_scope(self, node, scope):
# For all buffers, insert extra variables in the scope.
# The variables are also accessible from the buffer_info
# on the buffer entry
bufvars = [entry for name, entry
in scope.entries.iteritems()
if entry.type.is_buffer]
if len(bufvars) > 0:
self.buffers_exists = True
if isinstance(node, ModuleNode) and len(bufvars) > 0:
# for now...note that pos is wrong
raise CompileError(node.pos, "Buffer vars not allowed in module scope")
for entry in bufvars:
if entry.type.dtype.is_ptr:
raise CompileError(node.pos, "Buffers with pointer types not yet supported.")
name = entry.name
buftype = entry.type
if buftype.ndim > self.max_ndim:
self.max_ndim = buftype.ndim
# Declare auxiliary vars
cname = scope.mangle(Naming.bufstruct_prefix, name)
bufinfo = scope.declare_var(name="$%s" % cname, cname=cname,
type=PyrexTypes.c_py_buffer_type, pos=node.pos)
if entry.is_arg:
bufinfo.used = True # otherwise, NameNode will mark whether it is used
def var(prefix, idx, initval):
cname = scope.mangle(prefix, "%d_%s" % (idx, name))
result = scope.declare_var("$%s" % cname, PyrexTypes.c_py_ssize_t_type,
node.pos, cname=cname, is_cdef=True)
result.init = initval
if entry.is_arg:
result.used = True
return result
stridevars = [var(Naming.bufstride_prefix, i, "0") for i in range(entry.type.ndim)]
shapevars = [var(Naming.bufshape_prefix, i, "0") for i in range(entry.type.ndim)]
mode = entry.type.mode
if mode == 'full':
suboffsetvars = [var(Naming.bufsuboffset_prefix, i, "-1") for i in range(entry.type.ndim)]
else:
suboffsetvars = None
entry.buffer_aux = Symtab.BufferAux(bufinfo, stridevars, shapevars, suboffsetvars)
scope.buffer_entries = bufvars
self.scope = scope
def visit_ModuleNode(self, node):
self.handle_scope(node, node.scope)
self.visitchildren(node)
return node
def visit_FuncDefNode(self, node):
self.handle_scope(node, node.local_scope)
self.visitchildren(node)
return node
#
# Analysis
#
buffer_options = ("dtype", "ndim", "mode", "negative_indices", "cast") # ordered!
buffer_defaults = {"ndim": 1, "mode": "full", "negative_indices": True, "cast": False}
buffer_positional_options_count = 1 # anything beyond this needs keyword argument
ERR_BUF_OPTION_UNKNOWN = '"%s" is not a buffer option'
ERR_BUF_TOO_MANY = 'Too many buffer options'
ERR_BUF_DUP = '"%s" buffer option already supplied'
ERR_BUF_MISSING = '"%s" missing'
ERR_BUF_MODE = 'Only allowed buffer modes are: "c", "fortran", "full", "strided" (as a compile-time string)'
ERR_BUF_NDIM = 'ndim must be a non-negative integer'
ERR_BUF_DTYPE = 'dtype must be "object", numeric type or a struct'
ERR_BUF_BOOL = '"%s" must be a boolean'
def analyse_buffer_options(globalpos, env, posargs, dictargs, defaults=None, need_complete=True):
"""
Must be called during type analysis, as analyse is called
on the dtype argument.
posargs and dictargs should consist of a list and a dict
of tuples (value, pos). Defaults should be a dict of values.
Returns a dict containing all the options a buffer can have and
its value (with the positions stripped).
"""
if defaults is None:
defaults = buffer_defaults
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.iteritems():
if not name in buffer_options:
raise CompileError(pos, ERR_BUF_OPTION_UNKNOWN % name)
options[name] = value
for name, (value, pos) in zip(buffer_options, posargs):
if not name in buffer_options:
raise CompileError(pos, ERR_BUF_OPTION_UNKNOWN % name)
if name in options:
raise CompileError(pos, ERR_BUF_DUP % name)
options[name] = value
# Check that they are all there and copy defaults
for name in buffer_options:
if not name in options:
try:
options[name] = defaults[name]
except KeyError:
if need_complete:
raise CompileError(globalpos, ERR_BUF_MISSING % name)
dtype = options.get("dtype")
if dtype and dtype.is_extension_type:
raise CompileError(globalpos, ERR_BUF_DTYPE)
ndim = options.get("ndim")
if ndim and (not isinstance(ndim, int) or ndim < 0):
raise CompileError(globalpos, ERR_BUF_NDIM)
mode = options.get("mode")
if mode and not (mode in ('full', 'strided', 'c', 'fortran')):
raise CompileError(globalpos, ERR_BUF_MODE)
def assert_bool(name):
x = options.get(name)
if not isinstance(x, bool):
raise CompileError(globalpos, ERR_BUF_BOOL % name)
assert_bool('negative_indices')
assert_bool('cast')
return options
#
# Code generation
#
def get_flags(buffer_aux, buffer_type):
flags = 'PyBUF_FORMAT'
mode = buffer_type.mode
if mode == 'full':
flags += '| PyBUF_INDIRECT'
elif mode == 'strided':
flags += '| PyBUF_STRIDES'
elif mode == 'c':
flags += '| PyBUF_C_CONTIGUOUS'
elif mode == 'fortran':
flags += '| PyBUF_F_CONTIGUOUS'
else:
assert False
if buffer_aux.writable_needed: flags += "| PyBUF_WRITABLE"
return flags
def used_buffer_aux_vars(entry):
buffer_aux = entry.buffer_aux
buffer_aux.buffer_info_var.used = True
for s in buffer_aux.shapevars: s.used = True
for s in buffer_aux.stridevars: s.used = True
if buffer_aux.suboffsetvars:
for s in buffer_aux.suboffsetvars: s.used = True
def put_unpack_buffer_aux_into_scope(buffer_aux, mode, code):
# Generate code to copy the needed struct info into local
# variables.
bufstruct = buffer_aux.buffer_info_var.cname
varspec = [("strides", buffer_aux.stridevars),
("shape", buffer_aux.shapevars)]
if mode == 'full':
varspec.append(("suboffsets", buffer_aux.suboffsetvars))
for field, vars in varspec:
code.putln(" ".join(["%s = %s.%s[%d];" %
(s.cname, bufstruct, field, idx)
for idx, s in enumerate(vars)]))
def put_acquire_arg_buffer(entry, code, pos):
code.globalstate.use_utility_code(acquire_utility_code)
buffer_aux = entry.buffer_aux
getbuffer = get_getbuffer_call(code, entry.cname, buffer_aux, entry.type)
# Acquire any new buffer
code.putln("{")
code.putln("__Pyx_BufFmt_StackElem __pyx_stack[%d];" % entry.type.dtype.struct_nesting_depth())
code.putln(code.error_goto_if("%s == -1" % getbuffer, pos))
code.putln("}")
# An exception raised in arg parsing cannot be catched, so no
# need to care about the buffer then.
put_unpack_buffer_aux_into_scope(buffer_aux, entry.type.mode, code)
def put_release_buffer_code(code, entry):
code.globalstate.use_utility_code(acquire_utility_code)
code.putln("__Pyx_SafeReleaseBuffer(&%s);" % entry.buffer_aux.buffer_info_var.cname)
def get_getbuffer_call(code, obj_cname, buffer_aux, buffer_type):
ndim = buffer_type.ndim
cast = int(buffer_type.cast)
flags = get_flags(buffer_aux, buffer_type)
bufstruct = buffer_aux.buffer_info_var.cname
dtype_typeinfo = get_type_information_cname(code, buffer_type.dtype)
return ("__Pyx_GetBufferAndValidate(&%(bufstruct)s, "
"(PyObject*)%(obj_cname)s, &%(dtype_typeinfo)s, %(flags)s, %(ndim)d, "
"%(cast)d, __pyx_stack)" % locals())
def put_assign_to_buffer(lhs_cname, rhs_cname, buffer_aux, buffer_type,
is_initialized, pos, code):
"""
Generate code for reassigning a buffer variables. This only deals with getting
the buffer auxiliary structure and variables set up correctly, the assignment
itself and refcounting is the responsibility of the caller.
However, the assignment operation may throw an exception so that the reassignment
never happens.
Depending on the circumstances there are two possible outcomes:
- Old buffer released, new acquired, rhs assigned to lhs
- Old buffer released, new acquired which fails, reaqcuire old lhs buffer
(which may or may not succeed).
"""
code.globalstate.use_utility_code(acquire_utility_code)
bufstruct = buffer_aux.buffer_info_var.cname
flags = get_flags(buffer_aux, buffer_type)
code.putln("{") # Set up necesarry stack for getbuffer
code.putln("__Pyx_BufFmt_StackElem __pyx_stack[%d];" % buffer_type.dtype.struct_nesting_depth())
getbuffer = get_getbuffer_call(code, "%s", buffer_aux, buffer_type) # fill in object below
if is_initialized:
# Release any existing buffer
code.putln('__Pyx_SafeReleaseBuffer(&%s);' % bufstruct)
# Acquire
retcode_cname = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False)
code.putln("%s = %s;" % (retcode_cname, getbuffer % rhs_cname))
code.putln('if (%s) {' % (code.unlikely("%s < 0" % retcode_cname)))
# If acquisition failed, attempt to reacquire the old buffer
# before raising the exception. A failure of reacquisition
# will cause the reacquisition exception to be reported, one
# can consider working around this later.
type, value, tb = [code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=False)
for i in range(3)]
code.putln('PyErr_Fetch(&%s, &%s, &%s);' % (type, value, tb))
code.putln('if (%s) {' % code.unlikely("%s == -1" % (getbuffer % lhs_cname)))
code.putln('Py_XDECREF(%s); Py_XDECREF(%s); Py_XDECREF(%s);' % (type, value, tb)) # Do not refnanny these!
code.globalstate.use_utility_code(raise_buffer_fallback_code)
code.putln('__Pyx_RaiseBufferFallbackError();')
code.putln('} else {')
code.putln('PyErr_Restore(%s, %s, %s);' % (type, value, tb))
for t in (type, value, tb):
code.funcstate.release_temp(t)
code.putln('}')
code.putln('}')
# Unpack indices
put_unpack_buffer_aux_into_scope(buffer_aux, buffer_type.mode, code)
code.putln(code.error_goto_if_neg(retcode_cname, pos))
code.funcstate.release_temp(retcode_cname)
else:
# Our entry had no previous value, so set to None when acquisition fails.
# In this case, auxiliary vars should be set up right in initialization to a zero-buffer,
# so it suffices to set the buf field to NULL.
code.putln('if (%s) {' % code.unlikely("%s == -1" % (getbuffer % rhs_cname)))
code.putln('%s = %s; __Pyx_INCREF(Py_None); %s.buf = NULL;' %
(lhs_cname,
PyrexTypes.typecast(buffer_type, PyrexTypes.py_object_type, "Py_None"),
bufstruct))
code.putln(code.error_goto(pos))
code.put('} else {')
# Unpack indices
put_unpack_buffer_aux_into_scope(buffer_aux, buffer_type.mode, code)
code.putln('}')
code.putln("}") # Release stack
def put_buffer_lookup_code(entry, index_signeds, index_cnames, directives, pos, code):
"""
Generates code to process indices and calculate an offset into
a buffer. Returns a C string which gives a pointer which can be
read from or written to at will (it is an expression so caller should
store it in a temporary if it is used more than once).
As the bounds checking can have any number of combinations of unsigned
arguments, smart optimizations etc. we insert it directly in the function
body. The lookup however is delegated to a inline function that is instantiated
once per ndim (lookup with suboffsets tend to get quite complicated).
"""
bufaux = entry.buffer_aux
bufstruct = bufaux.buffer_info_var.cname
negative_indices = directives['wraparound'] and entry.type.negative_indices
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 dimension index the
# error is occuring at.
tmp_cname = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False)
code.putln("%s = -1;" % tmp_cname)
for dim, (signed, cname, shape) in enumerate(zip(index_signeds, index_cnames,
bufaux.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.cname))
code.putln("if (%s) %s = %d;" % (
code.unlikely("%s < 0" % cname), tmp_cname, dim))
else:
code.putln("%s = %d;" % (tmp_cname, dim))
code.put("} else ")
# check bounds in positive direction
if signed != 0:
cast = ""
else:
cast = "(size_t)"
code.putln("if (%s) %s = %d;" % (
code.unlikely("%s >= %s%s" % (cname, cast, shape.cname)),
tmp_cname, dim))
code.globalstate.use_utility_code(raise_indexerror_code)
code.putln("if (%s) {" % code.unlikely("%s != -1" % tmp_cname))
code.putln('__Pyx_RaiseBufferIndexError(%s);' % tmp_cname)
code.putln(code.error_goto(pos))
code.putln('}')
code.funcstate.release_temp(tmp_cname)
elif negative_indices:
# Only fix negative indices.
for signed, cname, shape in zip(index_signeds, index_cnames,
bufaux.shapevars):
if signed != 0:
code.putln("if (%s < 0) %s += %s;" % (cname, cname, shape.cname))
# Create buffer lookup and return it
# This is done via utility macros/inline functions, which vary
# according to the access mode used.
params = []
nd = entry.type.ndim
mode = entry.type.mode
if mode == 'full':
for i, s, o in zip(index_cnames, bufaux.stridevars, bufaux.suboffsetvars):
params.append(i)
params.append(s.cname)
params.append(o.cname)
funcname = "__Pyx_BufPtrFull%dd" % nd
funcgen = buf_lookup_full_code
else:
if mode == 'strided':
funcname = "__Pyx_BufPtrStrided%dd" % nd
funcgen = buf_lookup_strided_code
elif mode == 'c':
funcname = "__Pyx_BufPtrCContig%dd" % nd
funcgen = buf_lookup_c_code
elif mode == 'fortran':
funcname = "__Pyx_BufPtrFortranContig%dd" % nd
funcgen = buf_lookup_fortran_code
else:
assert False
for i, s in zip(index_cnames, bufaux.stridevars):
params.append(i)
params.append(s.cname)
# Make sure the utility code is available
if funcname not in code.globalstate.utility_codes:
code.globalstate.utility_codes.add(funcname)
protocode = code.globalstate['utility_code_proto']
defcode = code.globalstate['utility_code_def']
funcgen(protocode, defcode, name=funcname, nd=nd)
ptr_type = entry.type.buffer_ptr_type
ptrcode = "%s(%s, %s.buf, %s)" % (funcname,
ptr_type.declaration_code(""),
bufstruct,
", ".join(params))
return ptrcode
def use_empty_bufstruct_code(env, max_ndim):
code = dedent("""
Py_ssize_t __Pyx_zeros[] = {%s};
Py_ssize_t __Pyx_minusones[] = {%s};
""") % (", ".join(["0"] * max_ndim), ", ".join(["-1"] * max_ndim))
env.use_utility_code(UtilityCode(proto=code))
def buf_lookup_full_code(proto, defin, name, nd):
"""
Generates a buffer lookup function for the right number
of dimensions. The function gives back a void* at the right location.
"""
# _i_ndex, _s_tride, sub_o_ffset
macroargs = ", ".join(["i%d, s%d, o%d" % (i, i, i) for i in range(nd)])
proto.putln("#define %s(type, buf, %s) (type)(%s_imp(buf, %s))" % (name, macroargs, name, macroargs))
funcargs = ", ".join(["Py_ssize_t i%d, Py_ssize_t s%d, Py_ssize_t o%d" % (i, i, i) for i in range(nd)])
proto.putln("static CYTHON_INLINE void* %s_imp(void* buf, %s);" % (name, funcargs))
defin.putln(dedent("""
static CYTHON_INLINE void* %s_imp(void* buf, %s) {
char* ptr = (char*)buf;
""") % (name, funcargs) + "".join([dedent("""\
ptr += s%d * i%d;
if (o%d >= 0) ptr = *((char**)ptr) + o%d;
""") % (i, i, i, i) for i in range(nd)]
) + "\nreturn ptr;\n}")
def buf_lookup_strided_code(proto, defin, name, nd):
"""
Generates a buffer lookup function for the right number
of dimensions. The function gives back a void* at the right location.
"""
# _i_ndex, _s_tride
args = ", ".join(["i%d, s%d" % (i, i) for i in range(nd)])
offset = " + ".join(["i%d * s%d" % (i, i) for i in range(nd)])
proto.putln("#define %s(type, buf, %s) (type)((char*)buf + %s)" % (name, args, offset))
def buf_lookup_c_code(proto, defin, name, nd):
"""
Similar to strided lookup, but can assume that the last dimension
doesn't need a multiplication as long as.
Still we keep the same signature for now.
"""
if nd == 1:
proto.putln("#define %s(type, buf, i0, s0) ((type)buf + i0)" % name)
else:
args = ", ".join(["i%d, s%d" % (i, i) for i in range(nd)])
offset = " + ".join(["i%d * s%d" % (i, i) for i in range(nd - 1)])
proto.putln("#define %s(type, buf, %s) ((type)((char*)buf + %s) + i%d)" % (name, args, offset, nd - 1))
def buf_lookup_fortran_code(proto, defin, name, nd):
"""
Like C lookup, but the first index is optimized instead.
"""
if nd == 1:
proto.putln("#define %s(type, buf, i0, s0) ((type)buf + i0)" % name)
else:
args = ", ".join(["i%d, s%d" % (i, i) for i in range(nd)])
offset = " + ".join(["i%d * s%d" % (i, i) for i in range(1, nd)])
proto.putln("#define %s(type, buf, %s) ((type)((char*)buf + %s) + i%d)" % (name, args, offset, 0))
def use_py2_buffer_functions(env):
# Emulation of PyObject_GetBuffer and PyBuffer_Release for Python 2.
# For >= 2.6 we do double mode -- use the new buffer interface on objects
# which has the right tp_flags set, but emulation otherwise.
# Search all types for __getbuffer__ overloads
types = []
visited_scopes = set()
def find_buffer_types(scope):
if scope in visited_scopes:
return
visited_scopes.add(scope)
for m in scope.cimported_modules:
find_buffer_types(m)
for e in scope.type_entries:
t = e.type
if t.is_extension_type:
release = get = None
for x in t.scope.pyfunc_entries:
if x.name == u"__getbuffer__": get = x.func_cname
elif x.name == u"__releasebuffer__": release = x.func_cname
if get:
types.append((t.typeptr_cname, get, release))
find_buffer_types(env)
code = dedent("""
#if PY_MAJOR_VERSION < 3
static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags) {
#if PY_VERSION_HEX >= 0x02060000
if (Py_TYPE(obj)->tp_flags & Py_TPFLAGS_HAVE_NEWBUFFER)
return PyObject_GetBuffer(obj, view, flags);
#endif
""")
if len(types) > 0:
clause = "if"
for t, get, release in types:
code += " %s (PyObject_TypeCheck(obj, %s)) return %s(obj, view, flags);\n" % (clause, t, get)
clause = "else if"
code += " else {\n"
code += dedent("""\
PyErr_Format(PyExc_TypeError, "'%100s' does not have the buffer interface", Py_TYPE(obj)->tp_name);
return -1;
""", 2)
if len(types) > 0: code += " }"
code += dedent("""
}
static void __Pyx_ReleaseBuffer(Py_buffer *view) {
PyObject* obj = view->obj;
if (obj) {
""")
if len(types) > 0:
clause = "if"
for t, get, release in types:
if release:
code += "%s (PyObject_TypeCheck(obj, %s)) %s(obj, view);" % (clause, t, release)
clause = "else if"
code += dedent("""
Py_DECREF(obj);
view->obj = NULL;
}
}
#endif
""")
env.use_utility_code(UtilityCode(
proto = dedent("""\
#if PY_MAJOR_VERSION < 3
static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags);
static void __Pyx_ReleaseBuffer(Py_buffer *view);
#else
#define __Pyx_GetBuffer PyObject_GetBuffer
#define __Pyx_ReleaseBuffer PyBuffer_Release
#endif
"""), impl = code))
def mangle_dtype_name(dtype):
# Use prefixes to seperate user defined types from builtins
# (consider "typedef float unsigned_int")
if dtype.is_pyobject:
return "object"
elif dtype.is_ptr:
return "ptr"
else:
if dtype.is_typedef or dtype.is_struct_or_union:
prefix = "nn_"
else:
prefix = ""
return prefix + dtype.declaration_code("").replace(" ", "_")
def get_type_information_cname(code, dtype, maxdepth=None):
# Output the run-time type information (__Pyx_TypeInfo) for given dtype,
# and return the name of the type info struct.
#
# Structs with two floats of the same size are encoded as complex numbers.
# One can seperate between complex numbers declared as struct or with native
# encoding by inspecting to see if the fields field of the type is
# filled in.
namesuffix = mangle_dtype_name(dtype)
name = "__Pyx_TypeInfo_%s" % namesuffix
structinfo_name = "__Pyx_StructFields_%s" % namesuffix
if dtype.is_error: return ""
# It's critical that walking the type info doesn't use more stack
# depth than dtype.struct_nesting_depth() returns, so use an assertion for this
if maxdepth is None: maxdepth = dtype.struct_nesting_depth()
if maxdepth <= 0:
assert False
if name not in code.globalstate.utility_codes:
code.globalstate.utility_codes.add(name)
typecode = code.globalstate['typeinfo']
complex_possible = dtype.is_struct_or_union and dtype.can_be_complex()
declcode = dtype.declaration_code("")
if dtype.is_simple_buffer_dtype():
structinfo_name = "NULL"
elif dtype.is_struct:
fields = dtype.scope.var_entries
# Must pre-call all used types in order not to recurse utility code
# writing.
assert len(fields) > 0
types = [get_type_information_cname(code, f.type, maxdepth - 1)
for f in fields]
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.declaration_code(""), f.cname), safe=True)
typecode.putln(' {NULL, NULL, 0}', safe=True)
typecode.putln("};", safe=True)
else:
assert False
rep = str(dtype)
if dtype.is_int:
if dtype.signed == 0:
typegroup = 'U'
else:
typegroup = 'I'
elif complex_possible or dtype.is_complex:
typegroup = 'C'
elif dtype.is_float:
typegroup = 'R'
elif dtype.is_struct:
typegroup = 'S'
elif dtype.is_pyobject:
typegroup = 'O'
else:
print dtype
assert False
typecode.putln(('static __Pyx_TypeInfo %s = { "%s", %s, sizeof(%s), \'%s\' };'
) % (name,
rep,
structinfo_name,
declcode,
typegroup,
), safe=True)
return name
# Utility function to set the right exception
# The caller should immediately goto_error
raise_indexerror_code = UtilityCode(
proto = """\
static void __Pyx_RaiseBufferIndexError(int axis); /*proto*/
""",
impl = """\
static void __Pyx_RaiseBufferIndexError(int axis) {
PyErr_Format(PyExc_IndexError,
"Out of bounds on buffer access (axis %d)", axis);
}
""")
parse_typestring_repeat_code = UtilityCode(
proto = """
""",
impl = """
""")
raise_buffer_fallback_code = UtilityCode(
proto = """
static void __Pyx_RaiseBufferFallbackError(void); /*proto*/
""",
impl = """
static void __Pyx_RaiseBufferFallbackError(void) {
PyErr_Format(PyExc_ValueError,
"Buffer acquisition failed on assignment; and then reacquiring the old buffer failed too!");
}
""")
#
# Buffer format string checking
#
# Buffer type checking. Utility code for checking that acquired
# buffers match our assumptions. We only need to check ndim and
# the format string; the access mode/flags is checked by the
# exporter.
#
# The alignment code is copied from _struct.c in Python.
acquire_utility_code = UtilityCode(proto="""
/* Run-time type information about structs used with buffers */
struct __Pyx_StructField_;
typedef struct {
const char* name; /* for error messages only */
struct __Pyx_StructField_* fields;
size_t size; /* sizeof(type) */
char typegroup; /* _R_eal, _C_omplex, Signed _I_nt, _U_nsigned int, _S_truct, _P_ointer, _O_bject */
} __Pyx_TypeInfo;
typedef struct __Pyx_StructField_ {
__Pyx_TypeInfo* type;
const char* name;
size_t offset;
} __Pyx_StructField;
typedef struct {
__Pyx_StructField* field;
size_t parent_offset;
} __Pyx_BufFmt_StackElem;
static CYTHON_INLINE int __Pyx_GetBufferAndValidate(Py_buffer* buf, PyObject* obj, __Pyx_TypeInfo* dtype, int flags, int nd, int cast, __Pyx_BufFmt_StackElem* stack);
static CYTHON_INLINE void __Pyx_SafeReleaseBuffer(Py_buffer* info);
""", impl="""
static CYTHON_INLINE int __Pyx_IsLittleEndian(void) {
unsigned int n = 1;
return *(unsigned char*)(&n) != 0;
}
typedef struct {
__Pyx_StructField root;
__Pyx_BufFmt_StackElem* head;
size_t fmt_offset;
int new_count, enc_count;
int is_complex;
char enc_type;
char packmode;
} __Pyx_BufFmt_Context;
static void __Pyx_BufFmt_Init(__Pyx_BufFmt_Context* ctx,
__Pyx_BufFmt_StackElem* stack,
__Pyx_TypeInfo* type) {
stack[0].field = &ctx->root;
stack[0].parent_offset = 0;
ctx->root.type = type;
ctx->root.name = "buffer dtype";
ctx->root.offset = 0;
ctx->head = stack;
ctx->head->field = &ctx->root;
ctx->fmt_offset = 0;
ctx->head->parent_offset = 0;
ctx->packmode = '@';
ctx->new_count = 1;
ctx->enc_count = 0;
ctx->enc_type = 0;
ctx->is_complex = 0;
while (type->typegroup == 'S') {
++ctx->head;
ctx->head->field = type->fields;
ctx->head->parent_offset = 0;
type = type->fields->type;
}
}
static int __Pyx_BufFmt_ParseNumber(const char** ts) {
int count;
const char* t = *ts;
if (*t < '0' || *t > '9') {
return -1;
} else {
count = *t++ - '0';
while (*t >= '0' && *t < '9') {
count *= 10;
count += *t++ - '0';
}
}
*ts = t;
return count;
}
static void __Pyx_BufFmt_RaiseUnexpectedChar(char ch) {
char msg[] = {ch, 0};
PyErr_Format(PyExc_ValueError, "Unexpected format string character: '%s'", msg);
}
static const char* __Pyx_BufFmt_DescribeTypeChar(char ch, int is_complex) {
switch (ch) {
case 'b': return "'char'";
case 'B': return "'unsigned char'";
case 'h': return "'short'";
case 'H': return "'unsigned short'";
case 'i': return "'int'";
case 'I': return "'unsigned int'";
case 'l': return "'long'";
case 'L': return "'unsigned long'";
case 'q': return "'long long'";
case 'Q': return "'unsigned long long'";
case 'f': return (is_complex ? "'complex float'" : "'float'");
case 'd': return (is_complex ? "'complex double'" : "'double'");
case 'g': return (is_complex ? "'complex long double'" : "'long double'");
case 'T': return "a struct";
case 'O': return "Python object";
case 'P': return "a pointer";
case 0: return "end";
default: return "unparseable format string";
}
}
static size_t __Pyx_BufFmt_TypeCharToStandardSize(char ch, int is_complex) {
switch (ch) {
case '?': case 'c': case 'b': case 'B': return 1;
case 'h': case 'H': return 2;
case 'i': case 'I': case 'l': case 'L': return 4;
case 'q': case 'Q': return 8;
case 'f': return (is_complex ? 8 : 4);
case 'd': return (is_complex ? 16 : 8);
case 'g': {
PyErr_SetString(PyExc_ValueError, "Python does not define a standard format string size for long double ('g')..");
return 0;
}
case 'O': case 'P': return sizeof(void*);
default:
__Pyx_BufFmt_RaiseUnexpectedChar(ch);
return 0;
}
}
static size_t __Pyx_BufFmt_TypeCharToNativeSize(char ch, int is_complex) {
switch (ch) {
case 'c': case 'b': case 'B': return 1;
case 'h': case 'H': return sizeof(short);
case 'i': case 'I': return sizeof(int);
case 'l': case 'L': return sizeof(long);
#ifdef HAVE_LONG_LONG
case 'q': case 'Q': return sizeof(PY_LONG_LONG);
#endif
case 'f': return sizeof(float) * (is_complex ? 2 : 1);
case 'd': return sizeof(double) * (is_complex ? 2 : 1);
case 'g': return sizeof(long double) * (is_complex ? 2 : 1);
case 'O': case 'P': return sizeof(void*);
default: {
__Pyx_BufFmt_RaiseUnexpectedChar(ch);
return 0;
}
}
}
typedef struct { char c; short x; } __Pyx_st_short;
typedef struct { char c; int x; } __Pyx_st_int;
typedef struct { char c; long x; } __Pyx_st_long;
typedef struct { char c; float x; } __Pyx_st_float;
typedef struct { char c; double x; } __Pyx_st_double;
typedef struct { char c; long double x; } __Pyx_st_longdouble;
typedef struct { char c; void *x; } __Pyx_st_void_p;
#ifdef HAVE_LONG_LONG
typedef struct { char c; PY_LONG_LONG x; } __Pyx_s_long_long;
#endif
static size_t __Pyx_BufFmt_TypeCharToAlignment(char ch, int is_complex) {
switch (ch) {
case '?': case 'c': case 'b': case 'B': return 1;
case 'h': case 'H': return sizeof(__Pyx_st_short) - sizeof(short);
case 'i': case 'I': return sizeof(__Pyx_st_int) - sizeof(int);
case 'l': case 'L': return sizeof(__Pyx_st_long) - sizeof(long);
#ifdef HAVE_LONG_LONG
case 'q': case 'Q': return sizeof(__Pyx_s_long_long) - sizeof(PY_LONG_LONG);
#endif
case 'f': return sizeof(__Pyx_st_float) - sizeof(float);
case 'd': return sizeof(__Pyx_st_double) - sizeof(double);
case 'g': return sizeof(__Pyx_st_longdouble) - sizeof(long double);
case 'P': case 'O': return sizeof(__Pyx_st_void_p) - sizeof(void*);
default:
__Pyx_BufFmt_RaiseUnexpectedChar(ch);
return 0;
}
}
static size_t __Pyx_BufFmt_TypeCharToGroup(char ch, int is_complex) {
switch (ch) {
case 'c': case 'b': case 'h': case 'i': case 'l': case 'q': return 'I';
case 'B': case 'H': case 'I': case 'L': case 'Q': return 'U';
case 'f': case 'd': case 'g': return (is_complex ? 'C' : 'R');
case 'O': return 'O';
case 'P': return 'P';
default: {
__Pyx_BufFmt_RaiseUnexpectedChar(ch);
return 0;
}
}
}
static void __Pyx_BufFmt_RaiseExpected(__Pyx_BufFmt_Context* ctx) {
if (ctx->head == NULL || ctx->head->field == &ctx->root) {
const char* expected;
const char* quote;
if (ctx->head == NULL) {
expected = "end";
quote = "";
} else {
expected = ctx->head->field->type->name;
quote = "'";
}
PyErr_Format(PyExc_ValueError,
"Buffer dtype mismatch, expected %s%s%s but got %s",
quote, expected, quote,
__Pyx_BufFmt_DescribeTypeChar(ctx->enc_type, ctx->is_complex));
} else {
__Pyx_StructField* field = ctx->head->field;
__Pyx_StructField* parent = (ctx->head - 1)->field;
PyErr_Format(PyExc_ValueError,
"Buffer dtype mismatch, expected '%s' but got %s in '%s.%s'",
field->type->name, __Pyx_BufFmt_DescribeTypeChar(ctx->enc_type, ctx->is_complex),
parent->type->name, field->name);
}
}
static int __Pyx_BufFmt_ProcessTypeChunk(__Pyx_BufFmt_Context* ctx) {
char group;
size_t size, offset;
if (ctx->enc_type == 0) return 0;
group = __Pyx_BufFmt_TypeCharToGroup(ctx->enc_type, ctx->is_complex);
do {
__Pyx_StructField* field = ctx->head->field;
__Pyx_TypeInfo* type = field->type;
if (ctx->packmode == '@' || ctx->packmode == '^') {
size = __Pyx_BufFmt_TypeCharToNativeSize(ctx->enc_type, ctx->is_complex);
} else {
size = __Pyx_BufFmt_TypeCharToStandardSize(ctx->enc_type, ctx->is_complex);
}
if (ctx->packmode == '@') {
int align_at = __Pyx_BufFmt_TypeCharToAlignment(ctx->enc_type, ctx->is_complex);
int align_mod_offset;
if (align_at == 0) return -1;
align_mod_offset = ctx->fmt_offset % align_at;
if (align_mod_offset > 0) ctx->fmt_offset += align_at - align_mod_offset;
}
if (type->size != size || type->typegroup != group) {
if (type->typegroup == 'C' && type->fields != NULL) {
/* special case -- treat as struct rather than complex number */
size_t parent_offset = ctx->head->parent_offset + field->offset;
++ctx->head;
ctx->head->field = type->fields;
ctx->head->parent_offset = parent_offset;
continue;
}
__Pyx_BufFmt_RaiseExpected(ctx);
return -1;
}
offset = ctx->head->parent_offset + field->offset;
if (ctx->fmt_offset != offset) {
PyErr_Format(PyExc_ValueError,
"Buffer dtype mismatch; next field is at offset %"PY_FORMAT_SIZE_T"d "
"but %"PY_FORMAT_SIZE_T"d expected", ctx->fmt_offset, offset);
return -1;
}
ctx->fmt_offset += size;
--ctx->enc_count; /* Consume from buffer string */
/* Done checking, move to next field, pushing or popping struct stack if needed */
while (1) {
if (field == &ctx->root) {
ctx->head = NULL;
if (ctx->enc_count != 0) {
__Pyx_BufFmt_RaiseExpected(ctx);
return -1;
}
break; /* breaks both loops as ctx->enc_count == 0 */
}
ctx->head->field = ++field;
if (field->type == NULL) {
--ctx->head;
field = ctx->head->field;
continue;
} else if (field->type->typegroup == 'S') {
size_t parent_offset = ctx->head->parent_offset + field->offset;
if (field->type->fields->type == NULL) continue; /* empty struct */
field = field->type->fields;
++ctx->head;
ctx->head->field = field;
ctx->head->parent_offset = parent_offset;
break;
} else {
break;
}
}
} while (ctx->enc_count);
ctx->enc_type = 0;
ctx->is_complex = 0;
return 0;
}
static int __Pyx_BufFmt_FirstPack(__Pyx_BufFmt_Context* ctx) {
if (ctx->enc_type != 0 || ctx->packmode != '@') {
PyErr_SetString(PyExc_ValueError, "Buffer packing mode currently only allowed at beginning of format string (this is a defect)");
return -1;
}
return 0;
}
static const char* __Pyx_BufFmt_CheckString(__Pyx_BufFmt_Context* ctx, const char* ts) {
int got_Z = 0;
while (1) {
switch(*ts) {
case 0:
if (ctx->enc_type != 0 && ctx->head == NULL) {
__Pyx_BufFmt_RaiseExpected(ctx);
return NULL;
}
if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL;
if (ctx->head != NULL) {
__Pyx_BufFmt_RaiseExpected(ctx);
return NULL;
}
return ts;
case ' ':
case 10:
case 13:
++ts;
break;
case '<':
if (!__Pyx_IsLittleEndian()) {
PyErr_SetString(PyExc_ValueError, "Little-endian buffer not supported on big-endian compiler");
return NULL;
}
if (__Pyx_BufFmt_FirstPack(ctx) == -1) return NULL;
ctx->packmode = '=';
++ts;
break;
case '>':
case '!':
if (__Pyx_IsLittleEndian()) {
PyErr_SetString(PyExc_ValueError, "Big-endian buffer not supported on little-endian compiler");
return NULL;
}
if (__Pyx_BufFmt_FirstPack(ctx) == -1) return NULL;
ctx->packmode = '=';
++ts;
break;
case '=':
case '@':
case '^':
if (__Pyx_BufFmt_FirstPack(ctx) == -1) return NULL;
ctx->packmode = *ts++;
break;
case 'T': /* substruct */
{
int i;
const char* ts_after_sub;
int struct_count = ctx->new_count;
ctx->new_count = 1;
++ts;
if (*ts != '{') {
PyErr_SetString(PyExc_ValueError, "Buffer acquisition: Expected '{' after 'T'");
return NULL;
}
++ts;
ts_after_sub = ts;
for (i = 0; i != struct_count; ++i) {
ts_after_sub = __Pyx_BufFmt_CheckString(ctx, ts);
if (!ts_after_sub) return NULL;
}
ts = ts_after_sub;
}
break;
case '}': /* end of substruct; either repeat or move on */
++ts;
return ts;
case 'x':
if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL;
ctx->fmt_offset += ctx->new_count;
ctx->new_count = 1;
ctx->enc_count = 0;
ctx->enc_type = 0;
++ts;
break;
case 'Z':
got_Z = 1;
++ts;
if (*ts != 'f' && *ts != 'd' && *ts != 'g') {
__Pyx_BufFmt_RaiseUnexpectedChar('Z');
return NULL;
} /* fall through */
case 'c': case 'b': case 'B': case 'h': case 'H': case 'i': case 'I':
case 'l': case 'L': case 'q': case 'Q':
case 'f': case 'd': case 'g':
case 'O':
if (ctx->enc_type == *ts && got_Z == ctx->is_complex) {
/* Continue pooling same type */
ctx->enc_count += ctx->new_count;
} else {
/* New type */
if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL;
ctx->enc_count = ctx->new_count;
ctx->enc_type = *ts;
ctx->is_complex = got_Z;
}
++ts;
ctx->new_count = 1;
got_Z = 0;
break;
default:
{
ctx->new_count = __Pyx_BufFmt_ParseNumber(&ts);
if (ctx->new_count == -1) { /* First char was not a digit */
char msg[2] = { *ts, 0 };
PyErr_Format(PyExc_ValueError,
"Does not understand character buffer dtype format string ('%s')", msg);
return NULL;
}
}
}
}
}
static CYTHON_INLINE void __Pyx_ZeroBuffer(Py_buffer* buf) {
buf->buf = NULL;
buf->obj = NULL;
buf->strides = __Pyx_zeros;
buf->shape = __Pyx_zeros;
buf->suboffsets = __Pyx_minusones;
}
static CYTHON_INLINE int __Pyx_GetBufferAndValidate(Py_buffer* buf, PyObject* obj, __Pyx_TypeInfo* dtype, int flags, int nd, int cast, __Pyx_BufFmt_StackElem* stack) {
if (obj == Py_None) {
__Pyx_ZeroBuffer(buf);
return 0;
}
buf->buf = NULL;
if (__Pyx_GetBuffer(obj, buf, flags) == -1) goto fail;
if (buf->ndim != nd) {
PyErr_Format(PyExc_ValueError,
"Buffer has wrong number of dimensions (expected %d, got %d)",
nd, buf->ndim);
goto fail;
}
if (!cast) {
__Pyx_BufFmt_Context ctx;
__Pyx_BufFmt_Init(&ctx, stack, dtype);
if (!__Pyx_BufFmt_CheckString(&ctx, buf->format)) goto fail;
}
if ((unsigned)buf->itemsize != dtype->size) {
PyErr_Format(PyExc_ValueError,
"Item size of buffer (%"PY_FORMAT_SIZE_T"d byte%s) does not match size of '%s' (%"PY_FORMAT_SIZE_T"d byte%s)",
buf->itemsize, (buf->itemsize > 1) ? "s" : "",
dtype->name,
dtype->size, (dtype->size > 1) ? "s" : "");
goto fail;
}
if (buf->suboffsets == NULL) buf->suboffsets = __Pyx_minusones;
return 0;
fail:;
__Pyx_ZeroBuffer(buf);
return -1;
}
static CYTHON_INLINE void __Pyx_SafeReleaseBuffer(Py_buffer* info) {
if (info->buf == NULL) return;
if (info->suboffsets == __Pyx_minusones) info->suboffsets = NULL;
__Pyx_ReleaseBuffer(info);
}
""")
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Builtin.py 0000664 0000000 0000000 00000033511 11446142532 0024745 0 ustar 00root root 0000000 0000000 #
# Pyrex - Builtin Definitions
#
from Symtab import BuiltinScope, StructOrUnionScope
from Code import UtilityCode
from TypeSlots import Signature
import PyrexTypes
import Naming
builtin_function_table = [
# name, args, return, C API func, py equiv = "*"
('abs', "O", "O", "PyNumber_Absolute"),
#('chr', "", "", ""),
#('cmp', "", "", "", ""), # int PyObject_Cmp(PyObject *o1, PyObject *o2, int *result)
#('compile', "", "", ""), # PyObject* Py_CompileString( char *str, char *filename, int start)
('delattr', "OO", "r", "PyObject_DelAttr"),
('dir', "O", "O", "PyObject_Dir"),
('divmod', "OO", "O", "PyNumber_Divmod"),
('exec', "OOO", "O", "__Pyx_PyRun"),
#('eval', "", "", ""),
#('execfile', "", "", ""),
#('filter', "", "", ""),
#('getattr', "OO", "O", "PyObject_GetAttr"), # optimised later on
('getattr3', "OOO", "O", "__Pyx_GetAttr3", "getattr"),
('hasattr', "OO", "b", "PyObject_HasAttr"),
('hash', "O", "l", "PyObject_Hash"),
#('hex', "", "", ""),
#('id', "", "", ""),
#('input', "", "", ""),
('intern', "O", "O", "__Pyx_Intern"),
('isinstance', "OO", "b", "PyObject_IsInstance"),
('issubclass', "OO", "b", "PyObject_IsSubclass"),
#('iter', "O", "O", "PyObject_GetIter"), # optimised later on
('len', "O", "z", "PyObject_Length"),
('locals', "", "O", "__pyx_locals"),
#('map', "", "", ""),
#('max', "", "", ""),
#('min', "", "", ""),
#('oct', "", "", ""),
# Not worth doing open, when second argument would become mandatory
#('open', "ss", "O", "PyFile_FromString"),
#('ord', "", "", ""),
('pow', "OOO", "O", "PyNumber_Power"),
#('range', "", "", ""),
#('raw_input', "", "", ""),
#('reduce', "", "", ""),
('reload', "O", "O", "PyImport_ReloadModule"),
('repr', "O", "O", "PyObject_Repr"),
#('round', "", "", ""),
('setattr', "OOO", "r", "PyObject_SetAttr"),
#('sum', "", "", ""),
#('type', "O", "O", "PyObject_Type"),
#('unichr', "", "", ""),
#('unicode', "", "", ""),
#('vars', "", "", ""),
#('zip', "", "", ""),
# Can't do these easily until we have builtin type entries.
#('typecheck', "OO", "i", "PyObject_TypeCheck", False),
#('issubtype', "OO", "i", "PyType_IsSubtype", False),
# Put in namespace append optimization.
('__Pyx_PyObject_Append', "OO", "O", "__Pyx_PyObject_Append"),
]
# Builtin types
# bool
# buffer
# classmethod
# dict
# enumerate
# file
# float
# int
# list
# long
# object
# property
# slice
# staticmethod
# super
# str
# tuple
# type
# xrange
builtin_types_table = [
("type", "PyType_Type", []),
# This conflicts with the C++ bool type, and unfortunately
# C++ is too liberal about PyObject* <-> bool conversions,
# resulting in unintuitive runtime behavior and segfaults.
# ("bool", "PyBool_Type", []),
("int", "PyInt_Type", []),
("long", "PyLong_Type", []),
("float", "PyFloat_Type", []),
# Until we have a way to access attributes of a type,
# we don't want to make this one builtin.
# ("complex", "PyComplex_Type", []),
("bytes", "PyBytes_Type", []),
("str", "PyString_Type", []),
("unicode", "PyUnicode_Type", []),
("tuple", "PyTuple_Type", []),
("list", "PyList_Type", [("insert", "OzO", "i", "PyList_Insert")]),
("dict", "PyDict_Type", [("items", "O", "O", "PyDict_Items"),
("keys", "O", "O", "PyDict_Keys"),
("values","O", "O", "PyDict_Values"),
("copy", "O", "O", "PyDict_Copy")]),
("slice", "PySlice_Type", []),
("file", "PyFile_Type", []),
("set", "PySet_Type", [("clear", "O", "i", "PySet_Clear"),
("discard", "OO", "i", "PySet_Discard"),
("add", "OO", "i", "PySet_Add"),
("pop", "O", "O", "PySet_Pop")]),
("frozenset", "PyFrozenSet_Type", []),
]
types_that_construct_their_instance = (
# some builtin types do not always return an instance of
# themselves - these do:
'type', 'bool', 'long', 'float', 'bytes', 'unicode', 'tuple', 'list',
'dict', 'file', 'set', 'frozenset'
# 'str', # only in Py3.x
)
builtin_structs_table = [
('Py_buffer', 'Py_buffer',
[("buf", PyrexTypes.c_void_ptr_type),
("obj", PyrexTypes.py_object_type),
("len", PyrexTypes.c_py_ssize_t_type),
("itemsize", PyrexTypes.c_py_ssize_t_type),
("readonly", PyrexTypes.c_bint_type),
("ndim", PyrexTypes.c_int_type),
("format", PyrexTypes.c_char_ptr_type),
("shape", PyrexTypes.c_py_ssize_t_ptr_type),
("strides", PyrexTypes.c_py_ssize_t_ptr_type),
("suboffsets", PyrexTypes.c_py_ssize_t_ptr_type),
("internal", PyrexTypes.c_void_ptr_type),
])
]
getattr3_utility_code = UtilityCode(
proto = """
static PyObject *__Pyx_GetAttr3(PyObject *, PyObject *, PyObject *); /*proto*/
""",
impl = """
static PyObject *__Pyx_GetAttr3(PyObject *o, PyObject *n, PyObject *d) {
PyObject *r = PyObject_GetAttr(o, n);
if (!r) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
goto bad;
PyErr_Clear();
r = d;
Py_INCREF(d);
}
return r;
bad:
return 0;
}
""")
pyexec_utility_code = UtilityCode(
proto = """
#if PY_VERSION_HEX < 0x02040000
#ifndef Py_COMPILE_H
#include "compile.h"
#endif
#ifndef Py_EVAL_H
#include "eval.h"
#endif
#endif
static PyObject* __Pyx_PyRun(PyObject*, PyObject*, PyObject*);
""",
impl = """
static PyObject* __Pyx_PyRun(PyObject* o, PyObject* globals, PyObject* locals) {
PyObject* result;
PyObject* s = 0;
char *code = 0;
if (!globals || globals == Py_None) {
globals = PyModule_GetDict(%s);""" % Naming.module_cname + """
if (!globals)
goto bad;
} else if (!PyDict_Check(globals)) {
PyErr_Format(PyExc_TypeError, "exec() arg 2 must be a dict, not %.100s",
globals->ob_type->tp_name);
goto bad;
}
if (!locals || locals == Py_None) {
locals = globals;
}
if (PyDict_GetItemString(globals, "__builtins__") == NULL) {
PyDict_SetItemString(globals, "__builtins__", PyEval_GetBuiltins());
}
if (PyCode_Check(o)) {
if (PyCode_GetNumFree((PyCodeObject *)o) > 0) {
PyErr_SetString(PyExc_TypeError,
"code object passed to exec() may not contain free variables");
goto bad;
}
result = PyEval_EvalCode((PyCodeObject *)o, globals, locals);
} else {
PyCompilerFlags cf;
cf.cf_flags = 0;
if (PyUnicode_Check(o)) {
cf.cf_flags = PyCF_SOURCE_IS_UTF8;
s = PyUnicode_AsUTF8String(o);
if (!s) goto bad;
o = s;
#if PY_MAJOR_VERSION >= 3
} else if (!PyBytes_Check(o)) {
#else
} else if (!PyString_Check(o)) {
#endif
PyErr_SetString(PyExc_TypeError,
"exec: arg 1 must be string, bytes or code object");
goto bad;
}
#if PY_MAJOR_VERSION >= 3
code = PyBytes_AS_STRING(o);
#else
code = PyString_AS_STRING(o);
#endif
if (PyEval_MergeCompilerFlags(&cf)) {
result = PyRun_StringFlags(code, Py_file_input, globals, locals, &cf);
} else {
result = PyRun_String(code, Py_file_input, globals, locals);
}
Py_XDECREF(s);
}
return result;
bad:
Py_XDECREF(s);
return 0;
}
""")
intern_utility_code = UtilityCode(
proto = """
static PyObject* __Pyx_Intern(PyObject* s); /* proto */
""",
impl = '''
static PyObject* __Pyx_Intern(PyObject* s) {
if (!(likely(PyString_CheckExact(s)))) {
PyErr_Format(PyExc_TypeError, "Expected str, got %s", Py_TYPE(s)->tp_name);
return 0;
}
Py_INCREF(s);
#if PY_MAJOR_VERSION >= 3
PyUnicode_InternInPlace(&s);
#else
PyString_InternInPlace(&s);
#endif
return s;
}
''')
def put_py23_set_init_utility_code(code, pos):
code.putln("#if PY_VERSION_HEX < 0x02040000")
code.putln(code.error_goto_if_neg("__Pyx_Py23SetsImport()", pos))
code.putln("#endif")
py23_set_utility_code = UtilityCode(
proto = """
#if PY_VERSION_HEX < 0x02050000
#ifndef PyAnySet_CheckExact
#define PyAnySet_CheckExact(ob) \\
((ob)->ob_type == &PySet_Type || \\
(ob)->ob_type == &PyFrozenSet_Type)
#define PySet_New(iterable) \\
PyObject_CallFunctionObjArgs((PyObject *)&PySet_Type, (iterable), NULL)
#define Pyx_PyFrozenSet_New(iterable) \\
PyObject_CallFunctionObjArgs((PyObject *)&PyFrozenSet_Type, (iterable), NULL)
#define PySet_Size(anyset) \\
PyObject_Size((anyset))
#define PySet_Contains(anyset, key) \\
PySequence_Contains((anyset), (key))
#define PySet_Pop(set) \\
PyObject_CallMethod(set, (char *)"pop", NULL)
static CYTHON_INLINE int PySet_Clear(PyObject *set) {
PyObject *ret = PyObject_CallMethod(set, (char *)"clear", NULL);
if (!ret) return -1;
Py_DECREF(ret); return 0;
}
static CYTHON_INLINE int PySet_Discard(PyObject *set, PyObject *key) {
PyObject *ret = PyObject_CallMethod(set, (char *)"discard", (char *)"O", key);
if (!ret) return -1;
Py_DECREF(ret); return 0;
}
static CYTHON_INLINE int PySet_Add(PyObject *set, PyObject *key) {
PyObject *ret = PyObject_CallMethod(set, (char *)"add", (char *)"O", key);
if (!ret) return -1;
Py_DECREF(ret); return 0;
}
#endif /* PyAnySet_CheckExact (<= Py2.4) */
#if PY_VERSION_HEX < 0x02040000
#ifndef Py_SETOBJECT_H
#define Py_SETOBJECT_H
static PyTypeObject *__Pyx_PySet_Type = NULL;
static PyTypeObject *__Pyx_PyFrozenSet_Type = NULL;
#define PySet_Type (*__Pyx_PySet_Type)
#define PyFrozenSet_Type (*__Pyx_PyFrozenSet_Type)
#define PyAnySet_Check(ob) \\
(PyAnySet_CheckExact(ob) || \\
PyType_IsSubtype((ob)->ob_type, &PySet_Type) || \\
PyType_IsSubtype((ob)->ob_type, &PyFrozenSet_Type))
#define PyFrozenSet_CheckExact(ob) ((ob)->ob_type == &PyFrozenSet_Type)
static int __Pyx_Py23SetsImport(void) {
PyObject *sets=0, *Set=0, *ImmutableSet=0;
sets = PyImport_ImportModule((char *)"sets");
if (!sets) goto bad;
Set = PyObject_GetAttrString(sets, (char *)"Set");
if (!Set) goto bad;
ImmutableSet = PyObject_GetAttrString(sets, (char *)"ImmutableSet");
if (!ImmutableSet) goto bad;
Py_DECREF(sets);
__Pyx_PySet_Type = (PyTypeObject*) Set;
__Pyx_PyFrozenSet_Type = (PyTypeObject*) ImmutableSet;
return 0;
bad:
Py_XDECREF(sets);
Py_XDECREF(Set);
Py_XDECREF(ImmutableSet);
return -1;
}
#else
static int __Pyx_Py23SetsImport(void) { return 0; }
#endif /* !Py_SETOBJECT_H */
#endif /* < Py2.4 */
#endif /* < Py2.5 */
""",
init = put_py23_set_init_utility_code,
cleanup = """
#if PY_VERSION_HEX < 0x02040000
Py_XDECREF(__Pyx_PySet_Type); __Pyx_PySet_Type = NULL;
Py_XDECREF(__Pyx_PyFrozenSet_Type); __Pyx_PyFrozenSet_Type = NULL;
#endif /* < Py2.4 */
""")
builtin_utility_code = {
'exec' : pyexec_utility_code,
'getattr3' : getattr3_utility_code,
'intern' : intern_utility_code,
'set' : py23_set_utility_code,
'frozenset' : py23_set_utility_code,
}
builtin_scope = BuiltinScope()
def declare_builtin_func(name, args, ret, cname, py_equiv = "*"):
sig = Signature(args, ret)
type = sig.function_type()
utility = builtin_utility_code.get(name)
builtin_scope.declare_builtin_cfunction(name, type, cname, py_equiv, utility)
def init_builtin_funcs():
for desc in builtin_function_table:
declare_builtin_func(*desc)
builtin_types = {}
def init_builtin_types():
global builtin_types
for name, cname, funcs in builtin_types_table:
utility = builtin_utility_code.get(name)
the_type = builtin_scope.declare_builtin_type(name, cname, utility)
builtin_types[name] = the_type
for name, args, ret, cname in funcs:
sig = Signature(args, ret)
the_type.scope.declare_cfunction(name, sig.function_type(), None, cname)
def init_builtin_structs():
for name, cname, attribute_types in builtin_structs_table:
scope = StructOrUnionScope(name)
for attribute_name, attribute_type in attribute_types:
scope.declare_var(attribute_name, attribute_type, None,
attribute_name, allow_pyobject=True)
builtin_scope.declare_struct_or_union(
name, "struct", scope, 1, None, cname = cname)
def init_builtins():
init_builtin_funcs()
init_builtin_types()
init_builtin_structs()
global list_type, tuple_type, dict_type, set_type, frozenset_type
global bytes_type, str_type, unicode_type
global float_type, bool_type, type_type, complex_type
type_type = builtin_scope.lookup('type').type
list_type = builtin_scope.lookup('list').type
tuple_type = builtin_scope.lookup('tuple').type
dict_type = builtin_scope.lookup('dict').type
set_type = builtin_scope.lookup('set').type
frozenset_type = builtin_scope.lookup('frozenset').type
bytes_type = builtin_scope.lookup('bytes').type
str_type = builtin_scope.lookup('str').type
unicode_type = builtin_scope.lookup('unicode').type
float_type = builtin_scope.lookup('float').type
bool_type = builtin_scope.lookup('bool').type
complex_type = builtin_scope.lookup('complex').type
init_builtins()
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/CmdLine.py 0000664 0000000 0000000 00000015311 11446142532 0024650 0 ustar 00root root 0000000 0000000 #
# Cython - Command Line Parsing
#
import sys
import Options
usage = """\
Cython (http://cython.org) is a compiler for code written in the
Cython language. Cython is based on Pyrex by Greg Ewing.
Usage: cython [options] sourcefile.pyx ...
Options:
-V, --version Display version number of cython compiler
-l, --create-listing Write error messages to a listing file
-I, --include-dir Search for include files in named directory
(multiply include directories are allowed).
-o, --output-file Specify name of generated C file
-t, --timestamps Only compile newer source files (implied with -r)
-f, --force Compile all source files (overrides implied -t)
-q, --quiet Don't print module names in recursive mode
-v, --verbose Be verbose, print file names on multiple compilation
-p, --embed-positions If specified, the positions in Cython files of each
function definition is embedded in its docstring.
--cleanup Release interned objects on python exit, for memory debugging.
Level indicates aggressiveness, default 0 releases nothing.
-w, --working Sets the working directory for Cython (the directory modules
are searched from)
-D, --no-docstrings Remove docstrings.
-a, --annotate Produce a colorized HTML version of the source.
--line-directives Produce #line directives pointing to the .pyx source
--cplus Output a c++ rather than c file.
--embed Embed the Python interpreter in a main() method.
-2 Compile based on Python-2 syntax and code semantics.
-3 Compile based on Python-3 syntax and code semantics.
-X, --directive =[, 1:
sys.stderr.write(
"cython: Only one source file allowed when using -o\n")
sys.exit(1)
if len(sources) == 0 and not options.show_version:
bad_usage()
if Options.embed and len(sources) > 1:
sys.stderr.write(
"cython: Only one source file allowed when using -embed\n")
sys.exit(1)
return options, sources
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Code.py 0000664 0000000 0000000 00000135462 11446142532 0024221 0 ustar 00root root 0000000 0000000 #
# Pyrex - Code output module
#
import re
import Naming
import Options
import StringEncoding
from Cython import Utils
from Scanning import SourceDescriptor
from Cython.StringIOTree import StringIOTree
try:
set
except NameError:
from sets import Set as set
import DebugFlags
from Cython.Utils import none_or_sub
class UtilityCode(object):
# Stores utility code to add during code generation.
#
# See GlobalState.put_utility_code.
#
# hashes/equals by instance
def __init__(self, proto=None, impl=None, init=None, cleanup=None, requires=None,
proto_block='utility_code_proto'):
# proto_block: Which code block to dump prototype in. See GlobalState.
self.proto = proto
self.impl = impl
self.init = init
self.cleanup = cleanup
self.requires = requires
self._cache = {}
self.specialize_list = []
self.proto_block = proto_block
def specialize(self, pyrex_type=None, **data):
# Dicts aren't hashable...
if pyrex_type is not None:
data['type'] = pyrex_type.declaration_code('')
data['type_name'] = pyrex_type.specialization_name()
key = data.items(); key.sort(); key = tuple(key)
try:
return self._cache[key]
except KeyError:
if self.requires is None:
requires = None
else:
requires = [r.specialize(data) for r in self.requires]
s = self._cache[key] = UtilityCode(
none_or_sub(self.proto, data),
none_or_sub(self.impl, data),
none_or_sub(self.init, data),
none_or_sub(self.cleanup, data),
requires, self.proto_block)
self.specialize_list.append(s)
return s
def put_code(self, output):
if self.requires:
for dependency in self.requires:
output.use_utility_code(dependency)
if self.proto:
output[self.proto_block].put(self.proto)
if self.impl:
output['utility_code_def'].put(self.impl)
if self.init:
writer = output['init_globals']
if isinstance(self.init, basestring):
writer.put(self.init)
else:
self.init(writer, output.module_pos)
if self.cleanup and Options.generate_cleanup_code:
writer = output['cleanup_globals']
if isinstance(self.cleanup, basestring):
writer.put(self.cleanup)
else:
self.cleanup(writer, output.module_pos)
class FunctionState(object):
# return_label string function return point label
# error_label string error catch point label
# continue_label string loop continue point label
# break_label string loop break point label
# return_from_error_cleanup_label string
# label_counter integer counter for naming labels
# in_try_finally boolean inside try of try...finally
# exc_vars (string * 3) exception variables for reraise, or None
# Not used for now, perhaps later
def __init__(self, owner, names_taken=set()):
self.names_taken = names_taken
self.owner = owner
self.error_label = None
self.label_counter = 0
self.labels_used = {}
self.return_label = self.new_label()
self.new_error_label()
self.continue_label = None
self.break_label = None
self.in_try_finally = 0
self.exc_vars = None
self.temps_allocated = [] # of (name, type, manage_ref)
self.temps_free = {} # (type, manage_ref) -> list of free vars with same type/managed status
self.temps_used_type = {} # name -> (type, manage_ref)
self.temp_counter = 0
# labels
def new_label(self, name=None):
n = self.label_counter
self.label_counter = n + 1
label = "%s%d" % (Naming.label_prefix, n)
if name is not None:
label += '_' + name
return label
def new_error_label(self):
old_err_lbl = self.error_label
self.error_label = self.new_label('error')
return old_err_lbl
def get_loop_labels(self):
return (
self.continue_label,
self.break_label)
def set_loop_labels(self, labels):
(self.continue_label,
self.break_label) = labels
def new_loop_labels(self):
old_labels = self.get_loop_labels()
self.set_loop_labels(
(self.new_label("continue"),
self.new_label("break")))
return old_labels
def get_all_labels(self):
return (
self.continue_label,
self.break_label,
self.return_label,
self.error_label)
def set_all_labels(self, labels):
(self.continue_label,
self.break_label,
self.return_label,
self.error_label) = labels
def all_new_labels(self):
old_labels = self.get_all_labels()
new_labels = []
for old_label in old_labels:
if old_label:
new_labels.append(self.new_label())
else:
new_labels.append(old_label)
self.set_all_labels(new_labels)
return old_labels
def use_label(self, lbl):
self.labels_used[lbl] = 1
def label_used(self, lbl):
return lbl in self.labels_used
# temp handling
def allocate_temp(self, type, manage_ref):
"""
Allocates a temporary (which may create a new one or get a previously
allocated and released one of the same type). Type is simply registered
and handed back, but will usually be a PyrexType.
If type.is_pyobject, manage_ref comes into play. If manage_ref is set to
True, the temp will be decref-ed on return statements and in exception
handling clauses. Otherwise the caller has to deal with any reference
counting of the variable.
If not type.is_pyobject, then manage_ref will be ignored, but it
still has to be passed. It is recommended to pass False by convention
if it is known that type will never be a Python object.
A C string referring to the variable is returned.
"""
if not type.is_pyobject:
# Make manage_ref canonical, so that manage_ref will always mean
# a decref is needed.
manage_ref = False
freelist = self.temps_free.get((type, manage_ref))
if freelist is not None and len(freelist) > 0:
result = freelist.pop()
else:
while True:
self.temp_counter += 1
result = "%s%d" % (Naming.codewriter_temp_prefix, self.temp_counter)
if not result in self.names_taken: break
self.temps_allocated.append((result, type, manage_ref))
self.temps_used_type[result] = (type, manage_ref)
if DebugFlags.debug_temp_code_comments:
self.owner.putln("/* %s allocated */" % result)
return result
def release_temp(self, name):
"""
Releases a temporary so that it can be reused by other code needing
a temp of the same type.
"""
type, manage_ref = self.temps_used_type[name]
freelist = self.temps_free.get((type, manage_ref))
if freelist is None:
freelist = []
self.temps_free[(type, manage_ref)] = freelist
if name in freelist:
raise RuntimeError("Temp %s freed twice!" % name)
freelist.append(name)
if DebugFlags.debug_temp_code_comments:
self.owner.putln("/* %s released */" % name)
def temps_in_use(self):
"""Return a list of (cname,type,manage_ref) tuples of temp names and their type
that are currently in use.
"""
used = []
for name, type, manage_ref in self.temps_allocated:
freelist = self.temps_free.get((type, manage_ref))
if freelist is None or name not in freelist:
used.append((name, type, manage_ref))
return used
def temps_holding_reference(self):
"""Return a list of (cname,type) tuples of temp names and their type
that are currently in use. This includes only temps of a
Python object type which owns its reference.
"""
return [(name, type)
for name, type, manage_ref in self.temps_in_use()
if manage_ref]
def all_managed_temps(self):
"""Return a list of (cname, type) tuples of refcount-managed Python objects.
"""
return [(cname, type)
for cname, type, manage_ref in self.temps_allocated
if manage_ref]
def all_free_managed_temps(self):
"""Return a list of (cname, type) tuples of refcount-managed Python
objects that are not currently in use. This is used by
try-except and try-finally blocks to clean up temps in the
error case.
"""
return [(cname, type)
for (type, manage_ref), freelist in self.temps_free.iteritems()
if manage_ref
for cname in freelist]
class IntConst(object):
"""Global info about a Python integer constant held by GlobalState.
"""
# cname string
# value int
# is_long boolean
def __init__(self, cname, value, is_long):
self.cname = cname
self.value = value
self.is_long = is_long
class PyObjectConst(object):
"""Global info about a generic constant held by GlobalState.
"""
# cname string
# type PyrexType
def __init__(self, cname, type):
self.cname = cname
self.type = type
possible_unicode_identifier = re.compile(ur"(?![0-9])\w+$", re.U).match
possible_bytes_identifier = re.compile(r"(?![0-9])\w+$".encode('ASCII')).match
nice_identifier = re.compile(r'\A[a-zA-Z0-9_]+\Z').match
find_alphanums = re.compile('([a-zA-Z0-9]+)').findall
class StringConst(object):
"""Global info about a C string constant held by GlobalState.
"""
# cname string
# text EncodedString or BytesLiteral
# py_strings {(identifier, encoding) : PyStringConst}
def __init__(self, cname, text, byte_string):
self.cname = cname
self.text = text
self.escaped_value = StringEncoding.escape_byte_string(byte_string)
self.py_strings = None
def get_py_string_const(self, encoding, identifier=None, is_str=False):
py_strings = self.py_strings
text = self.text
is_str = bool(identifier or is_str)
is_unicode = encoding is None and not is_str
if encoding is None:
# unicode string
encoding_key = None
else:
# bytes or str
encoding = encoding.lower()
if encoding in ('utf8', 'utf-8', 'ascii', 'usascii', 'us-ascii'):
encoding = None
encoding_key = None
else:
encoding_key = ''.join(find_alphanums(encoding))
key = (is_str, is_unicode, encoding_key)
if py_strings is not None and key in py_strings:
py_string = py_strings[key]
else:
if py_strings is None:
self.py_strings = {}
if identifier:
intern = True
elif identifier is None:
if isinstance(text, unicode):
intern = bool(possible_unicode_identifier(text))
else:
intern = bool(possible_bytes_identifier(text))
else:
intern = False
if intern:
prefix = Naming.interned_str_prefix
else:
prefix = Naming.py_const_prefix
pystring_cname = "%s%s_%s" % (
prefix,
(is_str and 's') or (is_unicode and 'u') or 'b',
self.cname[len(Naming.const_prefix):])
py_string = PyStringConst(
pystring_cname, encoding, is_unicode, is_str, intern)
self.py_strings[key] = py_string
return py_string
class PyStringConst(object):
"""Global info about a Python string constant held by GlobalState.
"""
# cname string
# encoding string
# intern boolean
# is_unicode boolean
# is_str boolean
def __init__(self, cname, encoding, is_unicode, is_str=False, intern=False):
self.cname = cname
self.encoding = encoding
self.is_str = is_str
self.is_unicode = is_unicode
self.intern = intern
def __lt__(self, other):
return self.cname < other.cname
class GlobalState(object):
# filename_table {string : int} for finding filename table indexes
# filename_list [string] filenames in filename table order
# input_file_contents dict contents (=list of lines) of any file that was used as input
# to create this output C code. This is
# used to annotate the comments.
#
# utility_codes set IDs of used utility code (to avoid reinsertion)
#
# declared_cnames {string:Entry} used in a transition phase to merge pxd-declared
# constants etc. into the pyx-declared ones (i.e,
# check if constants are already added).
# In time, hopefully the literals etc. will be
# supplied directly instead.
#
# const_cname_counter int global counter for constant identifiers
#
# parts {string:CCodeWriter}
# interned_strings
# consts
# interned_nums
# directives set Temporary variable used to track
# the current set of directives in the code generation
# process.
directives = {}
code_layout = [
'h_code',
'filename_table',
'utility_code_proto_before_types',
'numeric_typedefs', # Let these detailed individual parts stay!,
'complex_type_declarations', # as the proper solution is to make a full DAG...
'type_declarations', # More coarse-grained blocks would simply hide
'utility_code_proto', # the ugliness, not fix it
'module_declarations',
'typeinfo',
'before_global_var',
'global_var',
'decls',
'all_the_rest',
'pystring_table',
'cached_builtins',
'init_globals',
'init_module',
'cleanup_globals',
'cleanup_module',
'main_method',
'utility_code_def',
'end'
]
def __init__(self, writer, emit_linenums=False):
self.filename_table = {}
self.filename_list = []
self.input_file_contents = {}
self.utility_codes = set()
self.declared_cnames = {}
self.in_utility_code_generation = False
self.emit_linenums = emit_linenums
self.parts = {}
self.const_cname_counter = 1
self.string_const_index = {}
self.int_const_index = {}
self.py_constants = []
assert writer.globalstate is None
writer.globalstate = self
self.rootwriter = writer
def initialize_main_c_code(self):
rootwriter = self.rootwriter
for part in self.code_layout:
self.parts[part] = rootwriter.insertion_point()
if not Options.cache_builtins:
del self.parts['cached_builtins']
else:
w = self.parts['cached_builtins']
w.enter_cfunc_scope()
w.putln("static int __Pyx_InitCachedBuiltins(void) {")
w = self.parts['init_globals']
w.enter_cfunc_scope()
w.putln("")
w.putln("static int __Pyx_InitGlobals(void) {")
if not Options.generate_cleanup_code:
del self.parts['cleanup_globals']
else:
w = self.parts['cleanup_globals']
w.enter_cfunc_scope()
w.putln("")
w.putln("static void __Pyx_CleanupGlobals(void) {")
#
# utility_code_def
#
code = self.parts['utility_code_def']
if self.emit_linenums:
code.write('\n#line 1 "cython_utility"\n')
code.putln("")
code.putln("/* Runtime support code */")
def finalize_main_c_code(self):
self.close_global_decls()
#
# utility_code_def
#
code = self.parts['utility_code_def']
import PyrexTypes
code.put(PyrexTypes.type_conversion_functions)
code.putln("")
def __getitem__(self, key):
return self.parts[key]
#
# Global constants, interned objects, etc.
#
def close_global_decls(self):
# This is called when it is known that no more global declarations will
# declared.
self.generate_const_declarations()
if Options.cache_builtins:
w = self.parts['cached_builtins']
w.putln("return 0;")
w.put_label(w.error_label)
w.putln("return -1;")
w.putln("}")
w.exit_cfunc_scope()
w = self.parts['init_globals']
w.putln("return 0;")
w.put_label(w.error_label)
w.putln("return -1;")
w.putln("}")
w.exit_cfunc_scope()
if Options.generate_cleanup_code:
w = self.parts['cleanup_globals']
w.putln("}")
w.exit_cfunc_scope()
if Options.generate_cleanup_code:
w = self.parts['cleanup_module']
w.putln("}")
w.exit_cfunc_scope()
def put_pyobject_decl(self, entry):
self['global_var'].putln("static PyObject *%s;" % entry.cname)
# constant handling at code generation time
def get_int_const(self, str_value, longness=False):
longness = bool(longness)
try:
c = self.int_const_index[(str_value, longness)]
except KeyError:
c = self.new_int_const(str_value, longness)
return c
def get_py_const(self, type):
# create a new Python object constant
return self.new_py_const(type)
def get_string_const(self, text):
# return a C string constant, creating a new one if necessary
if text.is_unicode:
byte_string = text.utf8encode()
else:
byte_string = text.byteencode()
try:
c = self.string_const_index[byte_string]
except KeyError:
c = self.new_string_const(text, byte_string)
return c
def get_py_string_const(self, text, identifier=None, is_str=False):
# return a Python string constant, creating a new one if necessary
c_string = self.get_string_const(text)
py_string = c_string.get_py_string_const(text.encoding, identifier, is_str)
return py_string
def get_interned_identifier(self, text):
return self.get_py_string_const(text, identifier=True)
def new_string_const(self, text, byte_string):
cname = self.new_string_const_cname(byte_string)
c = StringConst(cname, text, byte_string)
self.string_const_index[byte_string] = c
return c
def new_int_const(self, value, longness):
cname = self.new_int_const_cname(value, longness)
c = IntConst(cname, value, longness)
self.int_const_index[(value, longness)] = c
return c
def new_py_const(self, type):
cname = self.new_const_cname()
c = PyObjectConst(cname, type)
self.py_constants.append(c)
return c
def new_string_const_cname(self, bytes_value, intern=None):
# Create a new globally-unique nice name for a C string constant.
try:
value = bytes_value.decode('ASCII')
except UnicodeError:
return self.new_const_cname()
if len(value) < 20 and nice_identifier(value):
return "%s_%s" % (Naming.const_prefix, value)
else:
return self.new_const_cname()
def new_int_const_cname(self, value, longness):
if longness:
value += 'L'
cname = "%s%s" % (Naming.interned_num_prefix, value)
cname = cname.replace('-', 'neg_').replace('.','_')
return cname
def new_const_cname(self, prefix=''):
n = self.const_cname_counter
self.const_cname_counter += 1
return "%s%s%d" % (Naming.const_prefix, prefix, n)
def add_cached_builtin_decl(self, entry):
if Options.cache_builtins:
if self.should_declare(entry.cname, entry):
self.put_pyobject_decl(entry)
w = self.parts['cached_builtins']
if entry.name == 'xrange':
# replaced by range() in Py3
w.putln('#if PY_MAJOR_VERSION >= 3')
self.put_cached_builtin_init(
entry.pos, StringEncoding.EncodedString('range'),
entry.cname)
w.putln('#else')
self.put_cached_builtin_init(
entry.pos, StringEncoding.EncodedString(entry.name),
entry.cname)
if entry.name == 'xrange':
w.putln('#endif')
def put_cached_builtin_init(self, pos, name, cname):
w = self.parts['cached_builtins']
interned_cname = self.get_interned_identifier(name).cname
from ExprNodes import get_name_interned_utility_code
self.use_utility_code(get_name_interned_utility_code)
w.putln('%s = __Pyx_GetName(%s, %s); if (!%s) %s' % (
cname,
Naming.builtins_cname,
interned_cname,
cname,
w.error_goto(pos)))
def generate_const_declarations(self):
self.generate_string_constants()
self.generate_int_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.sort()
decls_writer = self.parts['decls']
for _, cname, c in consts:
decls_writer.putln(
"static %s;" % c.type.declaration_code(cname))
def generate_string_constants(self):
c_consts = [ (len(c.cname), c.cname, c)
for c in self.string_const_index.itervalues() ]
c_consts.sort()
py_strings = []
decls_writer = self.parts['decls']
for _, cname, c in c_consts:
decls_writer.putln('static char %s[] = "%s";' % (
cname, StringEncoding.split_string_literal(c.escaped_value)))
if c.py_strings is not None:
for py_string in c.py_strings.itervalues():
py_strings.append((c.cname, len(py_string.cname), py_string))
if py_strings:
import Nodes
self.use_utility_code(Nodes.init_string_tab_utility_code)
py_strings.sort()
w = self.parts['pystring_table']
w.putln("")
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'):
encoding = '0'
else:
encoding = '"%s"' % py_string.encoding.lower()
decls_writer.putln(
"static PyObject *%s;" % py_string.cname)
w.putln(
"{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % (
py_string.cname,
c_cname,
c_cname,
encoding,
py_string.is_unicode,
py_string.is_str,
py_string.intern
))
w.putln("{0, 0, 0, 0, 0, 0, 0}")
w.putln("};")
init_globals = self.parts['init_globals']
init_globals.putln(
"if (__Pyx_InitStrings(%s) < 0) %s;" % (
Naming.stringtab_cname,
init_globals.error_goto(self.module_pos)))
def generate_int_constants(self):
consts = [ (len(c.value), c.value, c.is_long, c)
for c in self.int_const_index.itervalues() ]
consts.sort()
decls_writer = self.parts['decls']
for _, value, longness, c in consts:
cname = c.cname
decls_writer.putln("static PyObject *%s;" % cname)
if longness:
function = '%s = PyLong_FromString((char *)"%s", 0, 0); %s;'
elif Utils.long_literal(value):
function = '%s = PyInt_FromString((char *)"%s", 0, 0); %s;'
else:
function = "%s = PyInt_FromLong(%s); %s;"
init_globals = self.parts['init_globals']
init_globals.putln(function % (
cname,
value,
init_globals.error_goto_if_null(cname, self.module_pos)))
# The functions below are there in a transition phase only
# and will be deprecated. They are called from Nodes.BlockNode.
# The copy&paste duplication is intentional in order to be able
# to see quickly how BlockNode worked, until this is replaced.
def should_declare(self, cname, entry):
if cname in self.declared_cnames:
other = self.declared_cnames[cname]
assert str(entry.type) == str(other.type)
assert entry.init == other.init
return False
else:
self.declared_cnames[cname] = entry
return True
#
# File name state
#
def lookup_filename(self, filename):
try:
index = self.filename_table[filename]
except KeyError:
index = len(self.filename_list)
self.filename_list.append(filename)
self.filename_table[filename] = index
return index
def commented_file_contents(self, source_desc):
try:
return self.input_file_contents[source_desc]
except KeyError:
F = [u' * ' + line.rstrip().replace(
u'*/', u'*[inserted by cython to avoid comment closer]/'
).replace(
u'/*', u'/[inserted by cython to avoid comment start]*'
)
for line in source_desc.get_lines(encoding='ASCII',
error_handling='ignore')]
if len(F) == 0: F.append(u'')
self.input_file_contents[source_desc] = F
return F
#
# Utility code state
#
def use_utility_code(self, utility_code):
"""
Adds code to the C file. utility_code should
a) implement __eq__/__hash__ for the purpose of knowing whether the same
code has already been included
b) implement put_code, which takes a globalstate instance
See UtilityCode.
"""
if utility_code not in self.utility_codes:
self.utility_codes.add(utility_code)
utility_code.put_code(self)
def funccontext_property(name):
try:
import operator
attribute_of = operator.attrgetter(name)
except:
def attribute_of(o):
return getattr(o, name)
def get(self):
return attribute_of(self.funcstate)
def set(self, value):
setattr(self.funcstate, name, value)
return property(get, set)
class CCodeWriter(object):
"""
Utility class to output C code.
When creating an insertion point one must care about the state that is
kept:
- formatting state (level, bol) is cloned and used in insertion points
as well
- labels, temps, exc_vars: One must construct a scope in which these can
exist by calling enter_cfunc_scope/exit_cfunc_scope (these are for
sanity checking and forward compatabilty). Created insertion points
looses this scope and cannot access it.
- marker: Not copied to insertion point
- filename_table, filename_list, input_file_contents: All codewriters
coming from the same root share the same instances simultaneously.
"""
# f file output file
# buffer StringIOTree
# level int indentation level
# bol bool beginning of line?
# marker string comment to emit before next line
# funcstate FunctionState contains state local to a C function used for code
# generation (labels and temps state etc.)
# globalstate GlobalState contains state global for a C file (input file info,
# utility code, declared constants etc.)
# emit_linenums boolean whether or not to write #line pragmas
#
# pyclass_stack list used during recursive code generation to pass information
# about the current class one is in
globalstate = None
def __init__(self, create_from=None, buffer=None, copy_formatting=False, emit_linenums=None):
if buffer is None: buffer = StringIOTree()
self.buffer = buffer
self.marker = None
self.last_marker_line = 0
self.source_desc = ""
self.pyclass_stack = []
self.funcstate = None
self.level = 0
self.call_level = 0
self.bol = 1
if create_from is not None:
# Use same global state
self.globalstate = create_from.globalstate
# Clone formatting state
if copy_formatting:
self.level = create_from.level
self.bol = create_from.bol
self.call_level = create_from.call_level
if emit_linenums is None and self.globalstate:
self.emit_linenums = self.globalstate.emit_linenums
else:
self.emit_linenums = emit_linenums
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)
return result
def copyto(self, f):
self.buffer.copyto(f)
def getvalue(self):
return self.buffer.getvalue()
def write(self, s):
self.buffer.write(s)
def insertion_point(self):
other = self.create_new(create_from=self, buffer=self.buffer.insertion_point(), copy_formatting=True)
return other
def new_writer(self):
"""
Creates a new CCodeWriter connected to the same global state, which
can later be inserted using insert.
"""
return CCodeWriter(create_from=self)
def insert(self, writer):
"""
Inserts the contents of another code writer (created with
the same global state) in the current location.
It is ok to write to the inserted writer also after insertion.
"""
assert writer.globalstate is self.globalstate
self.buffer.insert(writer.buffer)
# Properties delegated to function scope
label_counter = funccontext_property("label_counter")
return_label = funccontext_property("return_label")
error_label = funccontext_property("error_label")
labels_used = funccontext_property("labels_used")
continue_label = funccontext_property("continue_label")
break_label = funccontext_property("break_label")
return_from_error_cleanup_label = funccontext_property("return_from_error_cleanup_label")
# Functions delegated to function scope
def new_label(self, name=None): return self.funcstate.new_label(name)
def new_error_label(self): return self.funcstate.new_error_label()
def get_loop_labels(self): return self.funcstate.get_loop_labels()
def set_loop_labels(self, labels): return self.funcstate.set_loop_labels(labels)
def new_loop_labels(self): return self.funcstate.new_loop_labels()
def get_all_labels(self): return self.funcstate.get_all_labels()
def set_all_labels(self, labels): return self.funcstate.set_all_labels(labels)
def all_new_labels(self): return self.funcstate.all_new_labels()
def use_label(self, lbl): return self.funcstate.use_label(lbl)
def label_used(self, lbl): return self.funcstate.label_used(lbl)
def enter_cfunc_scope(self):
self.funcstate = FunctionState(self)
def exit_cfunc_scope(self):
self.funcstate = None
# constant handling
def get_py_num(self, str_value, longness):
return self.globalstate.get_int_const(str_value, longness).cname
def get_string_const(self, text):
return self.globalstate.get_string_const(text).cname
def get_py_string_const(self, text, identifier=None, is_str=False):
return self.globalstate.get_py_string_const(text, identifier, is_str).cname
def get_argument_default_const(self, type):
return self.globalstate.get_py_const(type).cname
def intern(self, text):
return self.get_py_string_const(text)
def intern_identifier(self, text):
return self.get_py_string_const(text, identifier=True)
# code generation
def putln(self, code = "", safe=False):
if self.marker and self.bol:
self.emit_marker()
if self.emit_linenums and self.last_marker_line != 0:
self.write('\n#line %s "%s"\n' % (self.last_marker_line, self.source_desc))
if code:
if safe:
self.put_safe(code)
else:
self.put(code)
self.write("\n");
self.bol = 1
def emit_marker(self):
self.write("\n");
self.indent()
self.write("/* %s */\n" % self.marker[1])
self.last_marker_line = self.marker[0]
self.marker = None
def put_safe(self, code):
# put code, but ignore {}
self.write(code)
self.bol = 0
def put(self, code):
fix_indent = False
if "{" in code:
dl = code.count("{")
else:
dl = 0
if "}" in code:
dl -= code.count("}")
if dl < 0:
self.level += dl
elif dl == 0 and code[0] == "}":
# special cases like "} else {" need a temporary dedent
fix_indent = True
self.level -= 1
if self.bol:
self.indent()
self.write(code)
self.bol = 0
if dl > 0:
self.level += dl
elif fix_indent:
self.level += 1
def increase_indent(self):
self.level = self.level + 1
def decrease_indent(self):
self.level = self.level - 1
def begin_block(self):
self.putln("{")
self.increase_indent()
def end_block(self):
self.decrease_indent()
self.putln("}")
def indent(self):
self.write(" " * self.level)
def get_py_version_hex(self, pyversion):
return "0x%02X%02X%02X%02X" % (tuple(pyversion) + (0,0,0,0))[:4]
def mark_pos(self, pos):
if pos is None:
return
source_desc, line, col = pos
if self.last_marker_line == line:
return
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]
marker = u'"%s":%d\n%s\n' % (
source_desc.get_escaped_description(), line, u'\n'.join(lines))
self.marker = (line, marker)
if self.emit_linenums:
self.source_desc = source_desc.get_escaped_description()
def put_label(self, lbl):
if lbl in self.funcstate.labels_used:
self.putln("%s:;" % lbl)
def put_goto(self, lbl):
self.funcstate.use_label(lbl)
self.putln("goto %s;" % lbl)
def put_var_declarations(self, entries, static = 0, dll_linkage = None,
definition = True):
for entry in entries:
if not entry.in_cinclude:
self.put_var_declaration(entry, static, dll_linkage, definition)
def put_var_declaration(self, entry, static = 0, dll_linkage = None,
definition = True):
#print "Code.put_var_declaration:", entry.name, "definition =", definition ###
if entry.in_closure:
return
visibility = entry.visibility
if visibility == 'private' and not definition:
#print "...private and not definition, skipping" ###
return
if not entry.used and visibility == "private":
#print "not used and private, skipping", entry.cname ###
return
storage_class = ""
if visibility == 'extern':
storage_class = Naming.extern_c_macro
elif visibility == 'public':
if not definition:
storage_class = Naming.extern_c_macro
elif visibility == 'private':
if static:
storage_class = "static"
if storage_class:
self.put("%s " % storage_class)
if visibility != 'public':
dll_linkage = None
self.put(entry.type.declaration_code(entry.cname,
dll_linkage = dll_linkage))
if entry.init is not None:
self.put_safe(" = %s" % entry.type.literal_code(entry.init))
self.putln(";")
def put_temp_declarations(self, func_context):
for name, type, manage_ref in func_context.temps_allocated:
decl = type.declaration_code(name)
if type.is_pyobject:
self.putln("%s = NULL;" % decl)
else:
self.putln("%s;" % decl)
def put_h_guard(self, guard):
self.putln("#ifndef %s" % guard)
self.putln("#define %s" % guard)
def unlikely(self, cond):
if Options.gcc_branch_hints:
return 'unlikely(%s)' % cond
else:
return cond
# Python objects and reference counting
def entry_as_pyobject(self, entry):
type = entry.type
if (not entry.is_self_arg and not entry.type.is_complete()
or entry.type.is_extension_type):
return "(PyObject *)" + entry.cname
else:
return entry.cname
def as_pyobject(self, cname, type):
from PyrexTypes import py_object_type, typecast
return typecast(py_object_type, type, cname)
def put_gotref(self, cname):
self.putln("__Pyx_GOTREF(%s);" % cname)
def put_giveref(self, cname):
self.putln("__Pyx_GIVEREF(%s);" % cname)
def put_xgiveref(self, cname):
self.putln("__Pyx_XGIVEREF(%s);" % cname)
def put_xgotref(self, cname):
self.putln("__Pyx_XGOTREF(%s);" % cname)
def put_incref(self, cname, type, nanny=True):
if nanny:
self.putln("__Pyx_INCREF(%s);" % self.as_pyobject(cname, type))
else:
self.putln("Py_INCREF(%s);" % self.as_pyobject(cname, type))
def put_decref(self, cname, type, nanny=True):
if nanny:
self.putln("__Pyx_DECREF(%s);" % self.as_pyobject(cname, type))
else:
self.putln("Py_DECREF(%s);" % self.as_pyobject(cname, type))
def put_var_gotref(self, entry):
if entry.type.is_pyobject:
self.putln("__Pyx_GOTREF(%s);" % self.entry_as_pyobject(entry))
def put_var_giveref(self, entry):
if entry.type.is_pyobject:
self.putln("__Pyx_GIVEREF(%s);" % self.entry_as_pyobject(entry))
def put_var_xgotref(self, entry):
if entry.type.is_pyobject:
self.putln("__Pyx_XGOTREF(%s);" % self.entry_as_pyobject(entry))
def put_var_xgiveref(self, entry):
if entry.type.is_pyobject:
self.putln("__Pyx_XGIVEREF(%s);" % self.entry_as_pyobject(entry))
def put_var_incref(self, entry):
if entry.type.is_pyobject:
self.putln("__Pyx_INCREF(%s);" % self.entry_as_pyobject(entry))
def put_decref_clear(self, cname, type, nanny=True):
from PyrexTypes import py_object_type, typecast
if nanny:
self.putln("__Pyx_DECREF(%s); %s = 0;" % (
typecast(py_object_type, type, cname), cname))
else:
self.putln("Py_DECREF(%s); %s = 0;" % (
typecast(py_object_type, type, cname), cname))
def put_xdecref(self, cname, type, nanny=True):
if nanny:
self.putln("__Pyx_XDECREF(%s);" % self.as_pyobject(cname, type))
else:
self.putln("Py_XDECREF(%s);" % self.as_pyobject(cname, type))
def put_xdecref_clear(self, cname, type, nanny=True):
if nanny:
self.putln("__Pyx_XDECREF(%s); %s = 0;" % (
self.as_pyobject(cname, type), cname))
else:
self.putln("Py_XDECREF(%s); %s = 0;" % (
self.as_pyobject(cname, type), cname))
def put_var_decref(self, entry):
if entry.type.is_pyobject:
if entry.init_to_none is False:
self.putln("__Pyx_XDECREF(%s);" % self.entry_as_pyobject(entry))
else:
self.putln("__Pyx_DECREF(%s);" % self.entry_as_pyobject(entry))
def put_var_decref_clear(self, entry):
if entry.type.is_pyobject:
self.putln("__Pyx_DECREF(%s); %s = 0;" % (
self.entry_as_pyobject(entry), entry.cname))
def put_var_xdecref(self, entry):
if entry.type.is_pyobject:
self.putln("__Pyx_XDECREF(%s);" % self.entry_as_pyobject(entry))
def put_var_xdecref_clear(self, entry):
if entry.type.is_pyobject:
self.putln("__Pyx_XDECREF(%s); %s = 0;" % (
self.entry_as_pyobject(entry), entry.cname))
def put_var_decrefs(self, entries, used_only = 0):
for entry in entries:
if not used_only or entry.used:
if entry.xdecref_cleanup:
self.put_var_xdecref(entry)
else:
self.put_var_decref(entry)
def put_var_xdecrefs(self, entries):
for entry in entries:
self.put_var_xdecref(entry)
def put_var_xdecrefs_clear(self, entries):
for entry in entries:
self.put_var_xdecref_clear(entry)
def put_init_to_py_none(self, cname, type, nanny=True):
from PyrexTypes import py_object_type, typecast
py_none = typecast(type, py_object_type, "Py_None")
if nanny:
self.putln("%s = %s; __Pyx_INCREF(Py_None);" % (cname, py_none))
else:
self.putln("%s = %s; Py_INCREF(Py_None);" % (cname, py_none))
def put_init_var_to_py_none(self, entry, template = "%s", nanny=True):
code = template % entry.cname
#if entry.type.is_extension_type:
# code = "((PyObject*)%s)" % code
self.put_init_to_py_none(code, entry.type, nanny)
def put_pymethoddef(self, entry, term, allow_skip=True):
if entry.is_special or entry.name == '__getattribute__':
if entry.name not in ['__cinit__', '__dealloc__', '__richcmp__', '__next__', '__getreadbuffer__', '__getwritebuffer__', '__getsegcount__', '__getcharbuffer__', '__getbuffer__', '__releasebuffer__', '__getattr__']:
# Python's typeobject.c will automatically fill in our slot
# in add_operators() (called by PyType_Ready) with a value
# that's better than ours.
if allow_skip:
return
from TypeSlots import method_coexist
if entry.doc:
doc_code = entry.doc_cname
else:
doc_code = 0
method_flags = entry.signature.method_flags()
if method_flags:
if entry.is_special:
method_flags += [method_coexist]
self.putln(
'{__Pyx_NAMESTR("%s"), (PyCFunction)%s, %s, __Pyx_DOCSTR(%s)}%s' % (
entry.name,
entry.func_cname,
"|".join(method_flags),
doc_code,
term))
# error handling
def put_error_if_neg(self, pos, value):
# return self.putln("if (unlikely(%s < 0)) %s" % (value, self.error_goto(pos))) # TODO this path is almost _never_ taken, yet this macro makes is slower!
return self.putln("if (%s < 0) %s" % (value, self.error_goto(pos)))
def set_error_info(self, pos):
if Options.c_line_in_traceback:
cinfo = " %s = %s;" % (Naming.clineno_cname, Naming.line_c_macro)
else:
cinfo = ""
return "%s = %s[%s]; %s = %s;%s" % (
Naming.filename_cname,
Naming.filetable_cname,
self.lookup_filename(pos[0]),
Naming.lineno_cname,
pos[1],
cinfo)
def error_goto(self, pos):
lbl = self.funcstate.error_label
self.funcstate.use_label(lbl)
return "{%s goto %s;}" % (
self.set_error_info(pos),
lbl)
def error_goto_if(self, cond, pos):
return "if (%s) %s" % (self.unlikely(cond), self.error_goto(pos))
def error_goto_if_null(self, cname, pos):
return self.error_goto_if("!%s" % cname, pos)
def error_goto_if_neg(self, cname, pos):
return self.error_goto_if("%s < 0" % cname, pos)
def error_goto_if_PyErr(self, pos):
return self.error_goto_if("PyErr_Occurred()", pos)
def lookup_filename(self, filename):
return self.globalstate.lookup_filename(filename)
def put_setup_refcount_context(self, name):
self.putln('__Pyx_RefNannySetupContext("%s");' % name)
def put_finish_refcount_context(self):
self.putln("__Pyx_RefNannyFinishContext();")
def put_trace_declarations(self):
self.putln('__Pyx_TraceDeclarations');
def put_trace_call(self, name, pos):
self.putln('__Pyx_TraceCall("%s", %s[%s], %s);' % (name, Naming.filetable_cname, self.lookup_filename(pos[0]), pos[1]));
def put_trace_exception(self):
self.putln("__Pyx_TraceException();")
def put_trace_return(self, retvalue_cname):
self.putln("__Pyx_TraceReturn(%s);" % retvalue_cname)
class PyrexCodeWriter(object):
# f file output file
# level int indentation level
def __init__(self, outfile_name):
self.f = Utils.open_new_file(outfile_name)
self.level = 0
def putln(self, code):
self.f.write("%s%s\n" % (" " * self.level, code))
def indent(self):
self.level += 1
def dedent(self):
self.level -= 1
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/CodeGeneration.py 0000664 0000000 0000000 00000002122 11446142532 0026217 0 ustar 00root root 0000000 0000000 from Cython.Compiler.Visitor import VisitorTransform, CythonTransform
from Cython.Compiler.ModuleNode import ModuleNode
from Cython.Compiler.Nodes import *
from Cython.Compiler.ExprNodes import *
class ExtractPxdCode(CythonTransform):
"""
Finds nodes in a pxd file that should generate code, and
returns them in a StatListNode.
The result is a tuple (StatListNode, ModuleScope), i.e.
everything that is needed from the pxd after it is processed.
A purer approach would be to seperately compile the pxd code,
but the result would have to be slightly more sophisticated
than pure strings (functions + wanted interned strings +
wanted utility code + wanted cached objects) so for now this
approach is taken.
"""
def __call__(self, root):
self.funcs = []
self.visitchildren(root)
return (StatListNode(root.pos, stats=self.funcs), root.scope)
def visit_FuncDefNode(self, node):
self.funcs.append(node)
# Do not visit children, nested funcdefnodes will
# also be moved by this action...
return node
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/ControlFlow.py 0000664 0000000 0000000 00000014757 11446142532 0025622 0 ustar 00root root 0000000 0000000 import bisect, sys
# This module keeps track of arbitrary "states" at any point of the code.
# A state is considered known if every path to the given point agrees on
# its state, otherwise it is None (i.e. unknown).
# It might be useful to be able to "freeze" the set of states by pushing
# all state changes to the tips of the trees for fast reading. Perhaps this
# could be done on get_state, clearing the cache on set_state (assuming
# incoming is immutable).
# This module still needs a lot of work, and probably should totally be
# redesigned. It doesn't take return, raise, continue, or break into
# account.
from Cython.Compiler.Scanning import StringSourceDescriptor
try:
_END_POS = (StringSourceDescriptor(unichr(sys.maxunicode)*10, ''),
sys.maxint, sys.maxint)
except AttributeError: # Py3
_END_POS = (StringSourceDescriptor(unichr(sys.maxunicode)*10, ''),
sys.maxsize, sys.maxsize)
class ControlFlow(object):
def __init__(self, start_pos, incoming, parent):
self.start_pos = start_pos
self.incoming = incoming
if parent is None and incoming is not None:
parent = incoming.parent
self.parent = parent
self.tip = {}
self.end_pos = _END_POS
def start_branch(self, pos):
self.end_pos = pos
branch_point = BranchingControlFlow(pos, self)
if self.parent is not None:
self.parent.branches[-1] = branch_point
return branch_point.branches[0]
def next_branch(self, pos):
self.end_pos = pos
return self.parent.new_branch(pos)
def finish_branch(self, pos):
self.end_pos = pos
self.parent.end_pos = pos
return LinearControlFlow(pos, self.parent)
def get_state(self, item, pos=_END_POS):
return self.get_pos_state(item, pos)[1]
def get_pos_state(self, item, pos=_END_POS):
# do some caching
if pos > self.end_pos:
try:
return self.tip[item]
except KeyError:
pass
pos_state = self._get_pos_state(item, pos)
if pos > self.end_pos:
self.tip[item] = pos_state
return pos_state
def _get_pos_state(self, item, pos):
current = self
while current is not None and pos <= current.start_pos:
current = current.incoming
if current is None:
return (None, None)
state = current._get_pos_state_local(item, pos)
while (state is None or state == (None, None)) and current.incoming is not None:
current = current.incoming
state = current._get_pos_state_local(item, pos)
if state is None:
return (None, None)
return state
def set_state(self, pos, item, state):
if item in self.tip:
del self.tip[item]
current = self
while pos < current.start_pos and current.incoming is not None:
current = current.incoming
if item in current.tip:
del current.tip[item]
current._set_state_local(pos, item, state)
class LinearControlFlow(ControlFlow):
def __init__(self, start_pos=(), incoming=None, parent=None):
ControlFlow.__init__(self, start_pos, incoming, parent)
self.events = {}
def _set_state_local(self, pos, item, state):
if item in self.events:
event_list = self.events[item]
else:
event_list = []
self.events[item] = event_list
bisect.insort(event_list, (pos, state))
def _get_pos_state_local(self, item, pos):
if item in self.events:
event_list = self.events[item]
for event in event_list[::-1]:
if event[0] < pos:
return event
return None
def to_string(self, indent='', limit=None):
if len(self.events) == 0:
s = indent + "[no state changes]"
else:
all = []
for item, event_list in self.events.items():
for pos, state in event_list:
all.append((indent, pos, item, state))
all.sort()
all = ["%s%s: %s <- %s" % data for data in all]
s = "\n".join(all)
if self.incoming is not limit and self.incoming is not None:
s = "%s\n%s" % (self.incoming.to_string(indent, limit=limit), s)
return s
class BranchingControlFlow(ControlFlow):
def __init__(self, start_pos, incoming, parent=None):
ControlFlow.__init__(self, start_pos, incoming, parent)
self.branches = [LinearControlFlow(start_pos, incoming, parent=self)]
self.branch_starts = [start_pos]
def _set_state_local(self, pos, item, state):
for branch_pos, branch in zip(self.branch_starts[::-1], self.branches[::-1]):
if pos >= branch_pos:
branch._set_state_local(pos, item, state)
return
def _get_pos_state_local(self, item, pos, stop_at=None):
if pos < self.end_pos:
for branch_pos, branch in zip(self.branch_starts[::-1], self.branches[::-1]):
if pos >= branch_pos:
return branch._get_pos_state_local(item, pos)
else:
state = self.branches[0]._get_pos_state_local(item, pos)
if state is None:
return None, None
last_pos, last_state = state
if last_state is None:
return None, None
for branch in self.branches[1:]:
state = branch._get_pos_state_local(item, pos)
if state is None:
return None, None
other_pos, other_state = state
if other_state != last_state:
return None, None
elif last_pos is not other_pos:
last_pos = max(last_pos, other_pos)
return last_pos, last_state
return None
def new_branch(self, pos):
self.branches.append(LinearControlFlow(pos, self.incoming, parent=self))
self.branch_starts.append(pos)
return self.branches[-1]
def to_string(self, indent='', limit=None):
join = "\n%sor\n" % indent
s = join.join([branch.to_string(indent+" ", limit=self.incoming) for branch in self.branches])
if self.incoming is not limit and self.incoming is not None:
s = "%s\n%s" % (self.incoming.to_string(indent, limit=limit), s)
return s
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/CythonScope.py 0000664 0000000 0000000 00000003451 11446142532 0025575 0 ustar 00root root 0000000 0000000 from Symtab import ModuleScope
from PyrexTypes import *
shape_func_type = CFuncType(
c_ptr_type(c_py_ssize_t_type),
[CFuncTypeArg("buffer", py_object_type, None)])
class CythonScope(ModuleScope):
def __init__(self, context):
ModuleScope.__init__(self, u'cython', None, context)
self.pxd_file_loaded = True
self.shape_entry = self.declare_cfunction('shape',
shape_func_type,
pos=None,
defining = 1,
cname='')
def lookup_type(self, name):
# This function should go away when types are all first-level objects.
type = parse_basic_type(name)
if type:
return type
def create_cython_scope(context):
create_utility_scope(context)
return CythonScope(context)
def create_utility_scope(context):
global utility_scope
utility_scope = ModuleScope(u'utility', None, context)
# These are used to optimize isinstance in FinalOptimizePhase
type_object = utility_scope.declare_typedef('PyTypeObject',
base_type = c_void_type,
pos = None,
cname = 'PyTypeObject')
type_object.is_void = True
utility_scope.declare_cfunction(
'PyObject_TypeCheck',
CFuncType(c_bint_type, [CFuncTypeArg("o", py_object_type, None),
CFuncTypeArg("t", c_ptr_type(type_object), None)]),
pos = None,
defining = 1,
cname = 'PyObject_TypeCheck')
return utility_scope
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/DebugFlags.py 0000664 0000000 0000000 00000001157 11446142532 0025343 0 ustar 00root root 0000000 0000000 # Can be enabled at the command line with --debug-xxx.
debug_disposal_code = 0
debug_temp_alloc = 0
debug_coercion = 0
# Write comments into the C code that show where temporary variables
# are allocated and released.
debug_temp_code_comments = 0
# Write a call trace of the code generation phase into the C code.
debug_trace_code_generation = 0
# Do not replace exceptions with user-friendly error messages.
debug_no_exception_intercept = 0
# Print a message each time a new stage in the pipeline is entered.
debug_verbose_pipeline = 0
# Raise an exception when an error is encountered.
debug_exception_on_error = 0
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Dependencies.py 0000664 0000000 0000000 00000037647 11446142532 0025743 0 ustar 00root root 0000000 0000000 from glob import glob
import re, os, sys
try:
set
except NameError:
# Python 2.3
from sets import Set as set
from distutils.extension import Extension
from Cython import Utils
# Unfortunately, Python 2.3 doesn't support decorators.
def cached_method(f):
cache_name = '__%s_cache' % f.__name__
def wrapper(self, *args):
cache = getattr(self, cache_name, None)
if cache is None:
cache = {}
setattr(self, cache_name, cache)
if args in cache:
return cache[args]
res = cache[args] = f(self, *args)
return res
return wrapper
def parse_list(s):
if s[0] == '[' and s[-1] == ']':
s = s[1:-1]
delimiter = ','
else:
delimiter = ' '
s, literals = strip_string_literals(s)
def unquote(literal):
literal = literal.strip()
if literal[0] == "'":
return literals[literal[1:-1]]
else:
return literal
return [unquote(item) for item in s.split(delimiter)]
transitive_str = object()
transitive_list = object()
distutils_settings = {
'name': str,
'sources': list,
'define_macros': list,
'undef_macros': list,
'libraries': transitive_list,
'library_dirs': transitive_list,
'runtime_library_dirs': transitive_list,
'include_dirs': transitive_list,
'extra_objects': list,
'extra_compile_args': list,
'extra_link_args': list,
'export_symbols': list,
'depends': transitive_list,
'language': transitive_str,
}
def line_iter(source):
start = 0
while True:
end = source.find('\n', start)
if end == -1:
yield source[start:]
return
yield source[start:end]
start = end+1
class DistutilsInfo(object):
def __init__(self, source=None, exn=None):
self.values = {}
if source is not None:
for line in line_iter(source):
line = line.strip()
if line != '' and line[0] != '#':
break
line = line[1:].strip()
if line[:10] == 'distutils:':
line = line[10:]
ix = line.index('=')
key = str(line[:ix].strip())
value = line[ix+1:].strip()
type = distutils_settings[key]
if type in (list, transitive_list):
value = parse_list(value)
if key == 'define_macros':
value = [tuple(macro.split('=')) for macro in value]
self.values[key] = value
elif exn is not None:
for key in self.distutils_settings:
if key in ('name', 'sources'):
pass
value = getattr(exn, key, None)
if value:
self.values[key] = value
def merge(self, other):
if other is None:
return self
for key, value in other.values.items():
type = distutils_settings[key]
if type is transitive_str and key not in self.values:
self.values[key] = value
elif type is transitive_list:
if key in self.values:
all = self.values[key]
for v in value:
if v not in all:
all.append(v)
else:
self.values[key] = value
return self
def subs(self, aliases):
if aliases is None:
return self
resolved = DistutilsInfo()
for key, value in self.values.items():
type = distutils_settings[key]
if type in [list, transitive_list]:
new_value_list = []
for v in value:
if v in aliases:
v = aliases[v]
if isinstance(v, list):
new_value_list += v
else:
new_value_list.append(v)
value = new_value_list
else:
if value in aliases:
value = aliases[value]
resolved.values[key] = value
return resolved
def strip_string_literals(code, prefix='__Pyx_L'):
"""
Normalizes every string literal to be of the form '__Pyx_Lxxx',
returning the normalized code and a mapping of labels to
string literals.
"""
new_code = []
literals = {}
counter = 0
start = q = 0
in_quote = False
raw = False
while True:
single_q = code.find("'", q)
double_q = code.find('"', q)
q = min(single_q, double_q)
if q == -1: q = max(single_q, double_q)
if q == -1:
if in_quote:
counter += 1
label = "'%s%s" % (prefix, counter)
literals[label] = code[start:]
new_code.append(label)
else:
new_code.append(code[start:])
break
elif in_quote:
if code[q-1] == '\\':
k = 2
while q >= k and code[q-k] == '\\':
k += 1
if k % 2 == 0:
q += 1
continue
if code[q:q+len(in_quote)] == in_quote:
counter += 1
label = "%s%s" % (prefix, counter)
literals[label] = code[start+len(in_quote):q]
new_code.append("'%s'" % label)
q += len(in_quote)
start = q
in_quote = False
else:
q += 1
else:
raw = False
if len(code) >= q+3 and (code[q+1] == code[q] == code[q+2]):
in_quote = code[q]*3
else:
in_quote = code[q]
end = q
while end>0 and code[end-1] in 'rRbBuU':
if code[end-1] in 'rR':
raw = True
end -= 1
new_code.append(code[start:end])
start = q
q += len(in_quote)
return "".join(new_code), literals
def parse_dependencies(source_filename):
# Actual parsing is way to slow, so we use regular expressions.
# The only catch is that we must strip comments and string
# literals ahead of time.
source = Utils.open_source_file(source_filename, "rU").read()
distutils_info = DistutilsInfo(source)
source = re.sub('#.*', '', source)
source, literals = strip_string_literals(source)
source = source.replace('\\\n', ' ')
if '\t' in source:
source = source.replace('\t', ' ')
# TODO: pure mode
dependancy = re.compile(r"(cimport +([0-9a-zA-Z_.]+)\b)|(from +([0-9a-zA-Z_.]+) +cimport)|(include +'([^']+)')|(cdef +extern +from +'([^']+)')")
cimports = []
includes = []
externs = []
for m in dependancy.finditer(source):
groups = m.groups()
if groups[0]:
cimports.append(groups[1])
elif groups[2]:
cimports.append(groups[3])
elif groups[4]:
includes.append(literals[groups[5]])
else:
externs.append(literals[groups[7]])
return cimports, includes, externs, distutils_info
class DependencyTree(object):
def __init__(self, context):
self.context = context
self._transitive_cache = {}
#@cached_method
def parse_dependencies(self, source_filename):
return parse_dependencies(source_filename)
parse_dependencies = cached_method(parse_dependencies)
#@cached_method
def cimports_and_externs(self, filename):
cimports, includes, externs = self.parse_dependencies(filename)[:3]
cimports = set(cimports)
externs = set(externs)
for include in includes:
a, b = self.cimports_and_externs(os.path.join(os.path.dirname(filename), include))
cimports.update(a)
externs.update(b)
return tuple(cimports), tuple(externs)
cimports_and_externs = cached_method(cimports_and_externs)
def cimports(self, filename):
return self.cimports_and_externs(filename)[0]
#@cached_method
def package(self, filename):
dir = os.path.dirname(filename)
if os.path.exists(os.path.join(dir, '__init__.py')):
return self.package(dir) + (os.path.basename(dir),)
else:
return ()
package = cached_method(package)
#@cached_method
def fully_qualifeid_name(self, filename):
module = os.path.splitext(os.path.basename(filename))[0]
return '.'.join(self.package(filename) + (module,))
fully_qualifeid_name = cached_method(fully_qualifeid_name)
def find_pxd(self, module, filename=None):
if module[0] == '.':
raise NotImplementedError, "New relative imports."
if filename is not None:
relative = '.'.join(self.package(filename) + tuple(module.split('.')))
pxd = self.context.find_pxd_file(relative, None)
if pxd:
return pxd
return self.context.find_pxd_file(module, None)
#@cached_method
def cimported_files(self, filename):
if filename[-4:] == '.pyx' and os.path.exists(filename[:-4] + '.pxd'):
self_pxd = [filename[:-4] + '.pxd']
else:
self_pxd = []
a = self.cimports(filename)
b = filter(None, [self.find_pxd(m, filename) for m in self.cimports(filename)])
if len(a) != len(b):
print (filename)
print ("\n\t".join(a))
print ("\n\t".join(b))
return tuple(self_pxd + filter(None, [self.find_pxd(m, filename) for m in self.cimports(filename)]))
cimported_files = cached_method(cimported_files)
def immediate_dependencies(self, filename):
all = list(self.cimported_files(filename))
for extern in self.cimports_and_externs(filename):
all.append(os.path.normpath(os.path.join(os.path.dirname(filename), extern)))
return tuple(all)
#@cached_method
def timestamp(self, filename):
return os.path.getmtime(filename)
timestamp = cached_method(timestamp)
def extract_timestamp(self, filename):
# TODO: .h files from extern blocks
return self.timestamp(filename), filename
def newest_dependency(self, filename):
return self.transitive_merge(filename, self.extract_timestamp, max)
def distutils_info0(self, filename):
return self.parse_dependencies(filename)[3]
def distutils_info(self, filename, aliases=None, base=None):
return (self.transitive_merge(filename, self.distutils_info0, DistutilsInfo.merge)
.subs(aliases)
.merge(base))
def transitive_merge(self, node, extract, merge):
try:
seen = self._transitive_cache[extract, merge]
except KeyError:
seen = self._transitive_cache[extract, merge] = {}
return self.transitive_merge_helper(
node, extract, merge, seen, {}, self.cimported_files)[0]
def transitive_merge_helper(self, node, extract, merge, seen, stack, outgoing):
if node in seen:
return seen[node], None
deps = extract(node)
if node in stack:
return deps, node
try:
stack[node] = len(stack)
loop = None
for next in outgoing(node):
sub_deps, sub_loop = self.transitive_merge_helper(next, extract, merge, seen, stack, outgoing)
if sub_loop is not None:
if loop is not None and stack[loop] < stack[sub_loop]:
pass
else:
loop = sub_loop
deps = merge(deps, sub_deps)
if loop == node:
loop = None
if loop is None:
seen[node] = deps
return deps, loop
finally:
del stack[node]
_dep_tree = None
def create_dependency_tree(ctx=None):
global _dep_tree
if _dep_tree is None:
if ctx is None:
from Cython.Compiler.Main import Context, CompilationOptions
ctx = Context(["."], CompilationOptions())
_dep_tree = DependencyTree(ctx)
return _dep_tree
# TODO: Take common options.
# TODO: Symbolic names (e.g. for numpy.include_dirs()
def create_extension_list(patterns, ctx=None, aliases=None):
seen = set()
deps = create_dependency_tree(ctx)
if not isinstance(patterns, list):
patterns = [patterns]
module_list = []
for pattern in patterns:
if isinstance(pattern, str):
filepattern = pattern
template = None
name = '*'
base = None
exn_type = Extension
elif isinstance(pattern, Extension):
filepattern = pattern.sources[0]
if os.path.splitext(filepattern)[1] not in ('.py', '.pyx'):
# ignore non-cython modules
module_list.append(pattern)
continue
template = pattern
name = template.name
base = DistutilsInfo(template)
exn_type = type(template)
else:
raise TypeError, pattern
for file in glob(filepattern):
pkg = deps.package(file)
if name == '*':
name = deps.fully_qualifeid_name(file)
if name not in seen:
module_list.append(exn_type(name=name, sources=[file], **deps.distutils_info(file, aliases, base).values))
seen.add(name)
return module_list
def cythonize(module_list, ctx=None, nthreads=0, aliases=None):
module_list = create_extension_list(module_list, ctx=ctx, aliases=aliases)
deps = create_dependency_tree(ctx)
to_compile = []
for m in module_list:
new_sources = []
for source in m.sources:
base, ext = os.path.splitext(source)
if ext in ('.pyx', '.py'):
if m.language == 'c++':
c_file = base + '.cpp'
else:
c_file = base + '.c'
if os.path.exists(c_file):
c_timestamp = os.path.getmtime(c_file)
else:
c_timestamp = -1
# Priority goes first to modified files, second to direct
# dependents, and finally to indirect dependents.
if c_timestamp < deps.timestamp(source):
dep_timestamp, dep = deps.timestamp(source), source
priority = 0
else:
dep_timestamp, dep = deps.newest_dependency(source)
priority = 2 - (dep in deps.immediate_dependencies(source))
if c_timestamp < dep_timestamp:
print "Compiling", source, "because it depends on", dep
to_compile.append((priority, source, c_file))
new_sources.append(c_file)
else:
new_sources.append(source)
m.sources = new_sources
to_compile.sort()
# TODO: invoke directly
if nthreads:
# Requires multiprocessing (or Python >= 2.6)
try:
import multiprocessing
except ImportError:
print "multiprocessing required for parallel cythonization"
nthreads = 0
pool = multiprocessing.Pool(nthreads)
pool.map(cythonoize_one_helper, to_compile)
if not nthreads:
for priority, pyx_file, c_file in to_compile:
cythonoize_one(pyx_file, c_file)
return module_list
cython_py = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../cython.py'))
def cythonoize_one(pyx_file, c_file):
cmd = "%s %s %s -o %s" % (sys.executable, cython_py, pyx_file, c_file)
print cmd
if os.system(cmd) != 0:
raise CompilerError, pyx_file
def cythonoize_one_helper(m):
return cythonoize_one(*m[1:])
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Errors.py 0000664 0000000 0000000 00000014005 11446142532 0024610 0 ustar 00root root 0000000 0000000 #
# Pyrex - Errors
#
import sys
from Cython.Utils import open_new_file
from DebugFlags import debug_exception_on_error
class PyrexError(Exception):
pass
class PyrexWarning(Exception):
pass
def context(position):
source = position[0]
assert not (isinstance(source, unicode) or isinstance(source, str)), (
"Please replace filename strings with Scanning.FileSourceDescriptor instances %r" % source)
try:
F = list(source.get_lines())
except UnicodeDecodeError:
# file has an encoding problem
s = u"[unprintable code]\n"
else:
s = u''.join(F[max(0, position[1]-6):position[1]])
s = u'...\n%s%s^\n' % (s, u' '*(position[2]-1))
s = u'%s\n%s%s\n' % (u'-'*60, s, u'-'*60)
return s
def format_position(position):
if position:
return u"%s:%d:%d: " % (position[0].get_description(),
position[1], position[2])
return u''
def format_error(message, position):
if position:
pos_str = format_position(position)
cont = context(position)
message = u'\nError converting Pyrex file to C:\n%s\n%s%s' % (cont, pos_str, message or u'')
return message
class CompileError(PyrexError):
def __init__(self, position = None, message = u""):
self.position = position
self.message_only = message
self.reported = False
# Deprecated and withdrawn in 2.6:
# self.message = message
Exception.__init__(self, format_error(message, position))
class CompileWarning(PyrexWarning):
def __init__(self, position = None, message = ""):
self.position = position
# Deprecated and withdrawn in 2.6:
# self.message = message
Exception.__init__(self, format_position(position) + message)
class InternalError(Exception):
# If this is ever raised, there is a bug in the compiler.
def __init__(self, message):
self.message_only = message
Exception.__init__(self, u"Internal compiler error: %s"
% message)
class CompilerCrash(CompileError):
# raised when an unexpected exception occurs in a transform
def __init__(self, pos, context, message, cause, stacktrace=None):
if message:
message = u'\n' + message
else:
message = u'\n'
self.message_only = message
if context:
message = u"Compiler crash in %s%s" % (context, message)
if stacktrace:
import traceback
message += (
u'\n\nCompiler crash traceback from this point on:\n' +
u''.join(traceback.format_tb(stacktrace)))
if cause:
if not stacktrace:
message += u'\n'
message += u'%s: %s' % (cause.__class__.__name__, cause)
CompileError.__init__(self, pos, message)
class NoElementTreeInstalledException(PyrexError):
"""raised when the user enabled options.debug but no ElementTree
implementation was found
"""
listing_file = None
num_errors = 0
echo_file = None
def open_listing_file(path, echo_to_stderr = 1):
# Begin a new error listing. If path is None, no file
# is opened, the error counter is just reset.
global listing_file, num_errors, echo_file
if path is not None:
listing_file = open_new_file(path)
else:
listing_file = None
if echo_to_stderr:
echo_file = sys.stderr
else:
echo_file = None
num_errors = 0
def close_listing_file():
global listing_file
if listing_file:
listing_file.close()
listing_file = None
def report_error(err):
if error_stack:
error_stack[-1].append(err)
else:
global num_errors
# See Main.py for why dual reporting occurs. Quick fix for now.
if err.reported: return
err.reported = True
try: line = u"%s\n" % err
except UnicodeEncodeError:
# Python <= 2.5 does this for non-ASCII Unicode exceptions
line = format_error(getattr(err, 'message_only', "[unprintable exception message]"),
getattr(err, 'position', None)) + u'\n'
if listing_file:
try: listing_file.write(line)
except UnicodeEncodeError:
listing_file.write(line.encode('ASCII', 'replace'))
if echo_file:
try: echo_file.write(line)
except UnicodeEncodeError:
echo_file.write(line.encode('ASCII', 'replace'))
num_errors = num_errors + 1
def error(position, message):
#print "Errors.error:", repr(position), repr(message) ###
if position is None:
raise InternalError(message)
err = CompileError(position, message)
if debug_exception_on_error: raise Exception(err) # debug
report_error(err)
return err
LEVEL=1 # warn about all errors level 1 or higher
def message(position, message, level=1):
if level < LEVEL:
return
warn = CompileWarning(position, message)
line = "note: %s\n" % warn
if listing_file:
listing_file.write(line)
if echo_file:
echo_file.write(line)
return warn
def warning(position, message, level=0):
if level < LEVEL:
return
warn = CompileWarning(position, message)
line = "warning: %s\n" % warn
if listing_file:
listing_file.write(line)
if echo_file:
echo_file.write(line)
return warn
_warn_once_seen = {}
def warn_once(position, message, level=0):
if level < LEVEL or message in _warn_once_seen:
return
warn = CompileWarning(position, message)
line = "warning: %s\n" % warn
if listing_file:
listing_file.write(line)
if echo_file:
echo_file.write(line)
_warn_once_seen[message] = True
return warn
# These functions can be used to momentarily suppress errors.
error_stack = []
def hold_errors():
error_stack.append([])
def release_errors(ignore=False):
held_errors = error_stack.pop()
if not ignore:
for err in held_errors:
report_error(err)
def held_errors():
return error_stack[-1]
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/ExprNodes.py 0000775 0000000 0000000 00001042002 11446142532 0025245 0 ustar 00root root 0000000 0000000 #
# Pyrex - Parse tree nodes for expressions
#
import operator
from Errors import error, warning, warn_once, InternalError
from Errors import hold_errors, release_errors, held_errors, report_error
from Code import UtilityCode
import StringEncoding
import Naming
import Nodes
from Nodes import Node
import PyrexTypes
from PyrexTypes import py_object_type, c_long_type, typecast, error_type, \
unspecified_type
from Builtin import list_type, tuple_type, set_type, dict_type, \
unicode_type, str_type, bytes_type, type_type
import Builtin
import Symtab
import Options
from Cython import Utils
from Annotate import AnnotationItem
from Cython import Utils
from Cython.Debugging import print_call_chain
from DebugFlags import debug_disposal_code, debug_temp_alloc, \
debug_coercion
try:
set
except NameError:
from sets import Set as set
class NotConstant(object):
def __repr__(self):
return ""
not_a_constant = NotConstant()
constant_value_not_set = object()
# error messages when coercing from key[0] to key[1]
find_coercion_error = {
# string related errors
(Builtin.unicode_type, Builtin.bytes_type) : "Cannot convert Unicode string to 'bytes' implicitly, encoding required.",
(Builtin.unicode_type, Builtin.str_type) : "Cannot convert Unicode string to 'str' implicitly. This is not portable and requires explicit encoding.",
(Builtin.unicode_type, PyrexTypes.c_char_ptr_type) : "Unicode objects do not support coercion to C types.",
(Builtin.bytes_type, Builtin.unicode_type) : "Cannot convert 'bytes' object to unicode implicitly, decoding required",
(Builtin.bytes_type, Builtin.str_type) : "Cannot convert 'bytes' object to str implicitly. This is not portable to Py3.",
(Builtin.str_type, Builtin.unicode_type) : "str objects do not support coercion to unicode, use a unicode string literal instead (u'')",
(Builtin.str_type, Builtin.bytes_type) : "Cannot convert 'str' to 'bytes' implicitly. This is not portable.",
(Builtin.str_type, PyrexTypes.c_char_ptr_type) : "'str' objects do not support coercion to C types (use 'bytes'?).",
(PyrexTypes.c_char_ptr_type, Builtin.unicode_type) : "Cannot convert 'char*' to unicode implicitly, decoding required",
(PyrexTypes.c_uchar_ptr_type, Builtin.unicode_type) : "Cannot convert 'char*' to unicode implicitly, decoding required",
}.get
class ExprNode(Node):
# subexprs [string] Class var holding names of subexpr node attrs
# type PyrexType Type of the result
# result_code string Code fragment
# result_ctype string C type of result_code if different from type
# is_temp boolean Result is in a temporary variable
# is_sequence_constructor
# boolean Is a list or tuple constructor expression
# is_starred boolean Is a starred expression (e.g. '*a')
# saved_subexpr_nodes
# [ExprNode or [ExprNode or None] or None]
# Cached result of subexpr_nodes()
# use_managed_ref boolean use ref-counted temps/assignments/etc.
result_ctype = None
type = None
temp_code = None
old_temp = None # error checker for multiple frees etc.
use_managed_ref = True # can be set by optimisation transforms
# The Analyse Expressions phase for expressions is split
# into two sub-phases:
#
# Analyse Types
# Determines the result type of the expression based
# on the types of its sub-expressions, and inserts
# coercion nodes into the expression tree where needed.
# Marks nodes which will need to have temporary variables
# allocated.
#
# Allocate Temps
# Allocates temporary variables where needed, and fills
# in the result_code field of each node.
#
# ExprNode provides some convenience routines which
# perform both of the above phases. These should only
# be called from statement nodes, and only when no
# coercion nodes need to be added around the expression
# being analysed. In that case, the above two phases
# should be invoked separately.
#
# Framework code in ExprNode provides much of the common
# processing for the various phases. It makes use of the
# 'subexprs' class attribute of ExprNodes, which should
# contain a list of the names of attributes which can
# hold sub-nodes or sequences of sub-nodes.
#
# The framework makes use of a number of abstract methods.
# Their responsibilities are as follows.
#
# Declaration Analysis phase
#
# analyse_target_declaration
# Called during the Analyse Declarations phase to analyse
# the LHS of an assignment or argument of a del statement.
# Nodes which cannot be the LHS of an assignment need not
# implement it.
#
# Expression Analysis phase
#
# analyse_types
# - Call analyse_types on all sub-expressions.
# - Check operand types, and wrap coercion nodes around
# sub-expressions where needed.
# - Set the type of this node.
# - If a temporary variable will be required for the
# result, set the is_temp flag of this node.
#
# analyse_target_types
# Called during the Analyse Types phase to analyse
# the LHS of an assignment or argument of a del
# statement. Similar responsibilities to analyse_types.
#
# target_code
# Called by the default implementation of allocate_target_temps.
# Should return a C lvalue for assigning to the node. The default
# implementation calls calculate_result_code.
#
# check_const
# - Check that this node and its subnodes form a
# legal constant expression. If so, do nothing,
# otherwise call not_const.
#
# The default implementation of check_const
# assumes that the expression is not constant.
#
# check_const_addr
# - Same as check_const, except check that the
# expression is a C lvalue whose address is
# constant. Otherwise, call addr_not_const.
#
# The default implementation of calc_const_addr
# assumes that the expression is not a constant
# lvalue.
#
# Code Generation phase
#
# generate_evaluation_code
# - Call generate_evaluation_code for sub-expressions.
# - Perform the functions of generate_result_code
# (see below).
# - If result is temporary, call generate_disposal_code
# on all sub-expressions.
#
# A default implementation of generate_evaluation_code
# is provided which uses the following abstract methods:
#
# generate_result_code
# - Generate any C statements necessary to calculate
# the result of this node from the results of its
# sub-expressions.
#
# calculate_result_code
# - Should return a C code fragment evaluating to the
# result. This is only called when the result is not
# a temporary.
#
# generate_assignment_code
# Called on the LHS of an assignment.
# - Call generate_evaluation_code for sub-expressions.
# - Generate code to perform the assignment.
# - If the assignment absorbed a reference, call
# generate_post_assignment_code on the RHS,
# otherwise call generate_disposal_code on it.
#
# generate_deletion_code
# Called on an argument of a del statement.
# - Call generate_evaluation_code for sub-expressions.
# - Generate code to perform the deletion.
# - Call generate_disposal_code on all sub-expressions.
#
#
is_sequence_constructor = 0
is_attribute = 0
saved_subexpr_nodes = None
is_temp = 0
is_target = 0
is_starred = 0
constant_result = constant_value_not_set
try:
_get_child_attrs = operator.attrgetter('subexprs')
except AttributeError:
# Python 2.3
def _get_child_attrs(self):
return self.subexprs
child_attrs = property(fget=_get_child_attrs)
def not_implemented(self, method_name):
print_call_chain(method_name, "not implemented") ###
raise InternalError(
"%s.%s not implemented" %
(self.__class__.__name__, method_name))
def is_lvalue(self):
return 0
def is_ephemeral(self):
# An ephemeral node is one whose result is in
# a Python temporary and we suspect there are no
# other references to it. Certain operations are
# disallowed on such values, since they are
# likely to result in a dangling pointer.
return self.type.is_pyobject and self.is_temp
def subexpr_nodes(self):
# Extract a list of subexpression nodes based
# on the contents of the subexprs class attribute.
nodes = []
for name in self.subexprs:
item = getattr(self, name)
if item is not None:
if type(item) is list:
nodes.extend(item)
else:
nodes.append(item)
return nodes
def result(self):
if self.is_temp:
return self.temp_code
else:
return self.calculate_result_code()
def result_as(self, type = None):
# Return the result code cast to the specified C type.
return typecast(type, self.ctype(), self.result())
def py_result(self):
# Return the result code cast to PyObject *.
return self.result_as(py_object_type)
def ctype(self):
# Return the native C type of the result (i.e. the
# C type of the result_code expression).
return self.result_ctype or self.type
def get_constant_c_result_code(self):
# Return the constant value of this node as a result code
# string, or None if the node is not constant. This method
# can be called when the constant result code is required
# before the code generation phase.
#
# The return value is a string that can represent a simple C
# value, a constant C name or a constant C expression. If the
# node type depends on Python code, this must return None.
return None
def calculate_constant_result(self):
# Calculate the constant compile time result value of this
# expression and store it in ``self.constant_result``. Does
# nothing by default, thus leaving ``self.constant_result``
# unknown. If valid, the result can be an arbitrary Python
# value.
#
# This must only be called when it is assured that all
# sub-expressions have a valid constant_result value. The
# ConstantFolding transform will do this.
pass
def has_constant_result(self):
return self.constant_result is not constant_value_not_set and \
self.constant_result is not not_a_constant
def compile_time_value(self, denv):
# Return value of compile-time expression, or report error.
error(self.pos, "Invalid compile-time expression")
def compile_time_value_error(self, e):
error(self.pos, "Error in compile-time expression: %s: %s" % (
e.__class__.__name__, e))
# ------------- Declaration Analysis ----------------
def analyse_target_declaration(self, env):
error(self.pos, "Cannot assign to or delete this")
# ------------- Expression Analysis ----------------
def analyse_const_expression(self, env):
# Called during the analyse_declarations phase of a
# constant expression. Analyses the expression's type,
# checks whether it is a legal const expression,
# and determines its value.
self.analyse_types(env)
return self.check_const()
def analyse_expressions(self, env):
# Convenience routine performing both the Type
# Analysis and Temp Allocation phases for a whole
# expression.
self.analyse_types(env)
def analyse_target_expression(self, env, rhs):
# Convenience routine performing both the Type
# Analysis and Temp Allocation phases for the LHS of
# an assignment.
self.analyse_target_types(env)
def analyse_boolean_expression(self, env):
# Analyse expression and coerce to a boolean.
self.analyse_types(env)
bool = self.coerce_to_boolean(env)
return bool
def analyse_temp_boolean_expression(self, env):
# Analyse boolean expression and coerce result into
# a temporary. This is used when a branch is to be
# performed on the result and we won't have an
# opportunity to ensure disposal code is executed
# afterwards. By forcing the result into a temporary,
# we ensure that all disposal has been done by the
# time we get the result.
self.analyse_types(env)
return self.coerce_to_boolean(env).coerce_to_simple(env)
# --------------- Type Inference -----------------
def type_dependencies(self, env):
# Returns the list of entries whose types must be determined
# before the type of self can be infered.
if hasattr(self, 'type') and self.type is not None:
return ()
return sum([node.type_dependencies(env) for node in self.subexpr_nodes()], ())
def infer_type(self, env):
# Attempt to deduce the type of self.
# Differs from analyse_types as it avoids unnecessary
# analysis of subexpressions, but can assume everything
# in self.type_dependencies() has been resolved.
if hasattr(self, 'type') and self.type is not None:
return self.type
elif hasattr(self, 'entry') and self.entry is not None:
return self.entry.type
else:
self.not_implemented("infer_type")
# --------------- Type Analysis ------------------
def analyse_as_module(self, env):
# If this node can be interpreted as a reference to a
# cimported module, return its scope, else None.
return None
def analyse_as_type(self, env):
# If this node can be interpreted as a reference to a
# type, return that type, else None.
return None
def analyse_as_extension_type(self, env):
# If this node can be interpreted as a reference to an
# extension type, return its type, else None.
return None
def analyse_types(self, env):
self.not_implemented("analyse_types")
def analyse_target_types(self, env):
self.analyse_types(env)
def nogil_check(self, env):
# By default, any expression based on Python objects is
# prevented in nogil environments. Subtypes must override
# this if they can work without the GIL.
if self.type.is_pyobject:
self.gil_error()
def gil_assignment_check(self, env):
if env.nogil and self.type.is_pyobject:
error(self.pos, "Assignment of Python object not allowed without gil")
def check_const(self):
self.not_const()
return False
def not_const(self):
error(self.pos, "Not allowed in a constant expression")
def check_const_addr(self):
self.addr_not_const()
return False
def addr_not_const(self):
error(self.pos, "Address is not constant")
# ----------------- Result Allocation -----------------
def result_in_temp(self):
# Return true if result is in a temporary owned by
# this node or one of its subexpressions. Overridden
# by certain nodes which can share the result of
# a subnode.
return self.is_temp
def target_code(self):
# Return code fragment for use as LHS of a C assignment.
return self.calculate_result_code()
def calculate_result_code(self):
self.not_implemented("calculate_result_code")
# def release_target_temp(self, env):
# # Release temporaries used by LHS of an assignment.
# self.release_subexpr_temps(env)
def allocate_temp_result(self, code):
if self.temp_code:
raise RuntimeError("Temp allocated multiple times in %r: %r" % (self.__class__.__name__, self.pos))
type = self.type
if not type.is_void:
if type.is_pyobject:
type = PyrexTypes.py_object_type
self.temp_code = code.funcstate.allocate_temp(
type, manage_ref=self.use_managed_ref)
else:
self.temp_code = None
def release_temp_result(self, code):
if not self.temp_code:
if self.old_temp:
raise RuntimeError("temp %s released multiple times in %s" % (
self.old_temp, self.__class__.__name__))
else:
raise RuntimeError("no temp, but release requested in %s" % (
self.__class__.__name__))
code.funcstate.release_temp(self.temp_code)
self.old_temp = self.temp_code
self.temp_code = None
# ---------------- Code Generation -----------------
def make_owned_reference(self, code):
# If result is a pyobject, make sure we own
# a reference to it.
if self.type.is_pyobject and not self.result_in_temp():
code.put_incref(self.result(), self.ctype())
def generate_evaluation_code(self, code):
code.mark_pos(self.pos)
# Generate code to evaluate this node and
# its sub-expressions, and dispose of any
# temporary results of its sub-expressions.
self.generate_subexpr_evaluation_code(code)
if self.is_temp:
self.allocate_temp_result(code)
self.generate_result_code(code)
if self.is_temp:
# If we are temp we do not need to wait until this node is disposed
# before disposing children.
self.generate_subexpr_disposal_code(code)
self.free_subexpr_temps(code)
def generate_subexpr_evaluation_code(self, code):
for node in self.subexpr_nodes():
node.generate_evaluation_code(code)
def generate_result_code(self, code):
self.not_implemented("generate_result_code")
def generate_disposal_code(self, code):
if self.is_temp:
if self.type.is_pyobject:
code.put_decref_clear(self.result(), self.ctype())
else:
# Already done if self.is_temp
self.generate_subexpr_disposal_code(code)
def generate_subexpr_disposal_code(self, code):
# Generate code to dispose of temporary results
# of all sub-expressions.
for node in self.subexpr_nodes():
node.generate_disposal_code(code)
def generate_post_assignment_code(self, code):
if self.is_temp:
if self.type.is_pyobject:
code.putln("%s = 0;" % self.result())
else:
self.generate_subexpr_disposal_code(code)
def generate_assignment_code(self, rhs, code):
# Stub method for nodes which are not legal as
# the LHS of an assignment. An error will have
# been reported earlier.
pass
def generate_deletion_code(self, code):
# Stub method for nodes that are not legal as
# the argument of a del statement. An error
# will have been reported earlier.
pass
def free_temps(self, code):
if self.is_temp:
if not self.type.is_void:
self.release_temp_result(code)
else:
self.free_subexpr_temps(code)
def free_subexpr_temps(self, code):
for sub in self.subexpr_nodes():
sub.free_temps(code)
def generate_function_definitions(self, env, code):
pass
# ---------------- Annotation ---------------------
def annotate(self, code):
for node in self.subexpr_nodes():
node.annotate(code)
# ----------------- Coercion ----------------------
def coerce_to(self, dst_type, env):
# Coerce the result so that it can be assigned to
# something of type dst_type. If processing is necessary,
# wraps this node in a coercion node and returns that.
# Otherwise, returns this node unchanged.
#
# This method is called during the analyse_expressions
# phase of the src_node's processing.
#
# Note that subclasses that override this (especially
# ConstNodes) must not (re-)set their own .type attribute
# here. Since expression nodes may turn up in different
# places in the tree (e.g. inside of CloneNodes in cascaded
# assignments), this method must return a new node instance
# if it changes the type.
#
src = self
src_type = self.type
src_is_py_type = src_type.is_pyobject
dst_is_py_type = dst_type.is_pyobject
if self.check_for_coercion_error(dst_type):
return self
if dst_type.is_pyobject:
if not src.type.is_pyobject:
if dst_type is bytes_type and src.type.is_int:
src = CoerceIntToBytesNode(src, env)
else:
src = CoerceToPyTypeNode(src, env)
if not src.type.subtype_of(dst_type):
if not isinstance(src, NoneNode):
src = PyTypeTestNode(src, dst_type, env)
elif src.type.is_pyobject:
src = CoerceFromPyTypeNode(dst_type, src, env)
elif (dst_type.is_complex
and src_type != dst_type
and dst_type.assignable_from(src_type)):
src = CoerceToComplexNode(src, dst_type, env)
else: # neither src nor dst are py types
# Added the string comparison, since for c types that
# is enough, but Cython gets confused when the types are
# in different pxi files.
if not (str(src.type) == str(dst_type) or dst_type.assignable_from(src_type)):
self.fail_assignment(dst_type)
return src
def fail_assignment(self, dst_type):
error(self.pos, "Cannot assign type '%s' to '%s'" % (self.type, dst_type))
def check_for_coercion_error(self, dst_type, fail=False, default=None):
if fail and not default:
default = "Cannot assign type '%(FROM)s' to '%(TO)s'"
message = find_coercion_error((self.type, dst_type), default)
if message is not None:
error(self.pos, message % {'FROM': self.type, 'TO': dst_type})
return True
if fail:
self.fail_assignment(dst_type)
return True
return False
def coerce_to_pyobject(self, env):
return self.coerce_to(PyrexTypes.py_object_type, env)
def coerce_to_boolean(self, env):
# Coerce result to something acceptable as
# a boolean value.
# if it's constant, calculate the result now
if self.has_constant_result():
bool_value = bool(self.constant_result)
return BoolNode(self.pos, value=bool_value,
constant_result=bool_value)
type = self.type
if type.is_pyobject or type.is_ptr or type.is_float:
return CoerceToBooleanNode(self, env)
else:
if not (type.is_int or type.is_enum or type.is_error):
error(self.pos,
"Type '%s' not acceptable as a boolean" % type)
return self
def coerce_to_integer(self, env):
# If not already some C integer type, coerce to longint.
if self.type.is_int:
return self
else:
return self.coerce_to(PyrexTypes.c_long_type, env)
def coerce_to_temp(self, env):
# Ensure that the result is in a temporary.
if self.result_in_temp():
return self
else:
return CoerceToTempNode(self, env)
def coerce_to_simple(self, env):
# Ensure that the result is simple (see is_simple).
if self.is_simple():
return self
else:
return self.coerce_to_temp(env)
def is_simple(self):
# A node is simple if its result is something that can
# be referred to without performing any operations, e.g.
# a constant, local var, C global var, struct member
# reference, or temporary.
return self.result_in_temp()
def may_be_none(self):
return self.type.is_pyobject
def as_cython_attribute(self):
return None
def as_none_safe_node(self, message, error="PyExc_TypeError"):
# Wraps the node in a NoneCheckNode if it is not known to be
# not-None (e.g. because it is a Python literal).
if self.may_be_none():
return NoneCheckNode(self, error, message)
else:
return self
class AtomicExprNode(ExprNode):
# Abstract base class for expression nodes which have
# no sub-expressions.
subexprs = []
# Override to optimize -- we know we have no children
def generate_subexpr_evaluation_code(self, code):
pass
def generate_subexpr_disposal_code(self, code):
pass
class PyConstNode(AtomicExprNode):
# Abstract base class for constant Python values.
is_literal = 1
type = py_object_type
def is_simple(self):
return 1
def may_be_none(self):
return False
def analyse_types(self, env):
pass
def calculate_result_code(self):
return self.value
def generate_result_code(self, code):
pass
class NoneNode(PyConstNode):
# The constant value None
value = "Py_None"
constant_result = None
nogil_check = None
def compile_time_value(self, denv):
return None
def may_be_none(self):
return True
class EllipsisNode(PyConstNode):
# '...' in a subscript list.
value = "Py_Ellipsis"
constant_result = Ellipsis
def compile_time_value(self, denv):
return Ellipsis
class ConstNode(AtomicExprNode):
# Abstract base type for literal constant nodes.
#
# value string C code fragment
is_literal = 1
nogil_check = None
def is_simple(self):
return 1
def may_be_none(self):
return False
def analyse_types(self, env):
pass # Types are held in class variables
def check_const(self):
return True
def get_constant_c_result_code(self):
return self.calculate_result_code()
def calculate_result_code(self):
return str(self.value)
def generate_result_code(self, code):
pass
class BoolNode(ConstNode):
type = PyrexTypes.c_bint_type
# The constant value True or False
def calculate_constant_result(self):
self.constant_result = self.value
def compile_time_value(self, denv):
return self.value
def calculate_result_code(self):
return str(int(self.value))
class NullNode(ConstNode):
type = PyrexTypes.c_null_ptr_type
value = "NULL"
constant_result = 0
def get_constant_c_result_code(self):
return self.value
class CharNode(ConstNode):
type = PyrexTypes.c_char_type
def calculate_constant_result(self):
self.constant_result = ord(self.value)
def compile_time_value(self, denv):
return ord(self.value)
def calculate_result_code(self):
return "'%s'" % StringEncoding.escape_char(self.value)
class IntNode(ConstNode):
# unsigned "" or "U"
# longness "" or "L" or "LL"
unsigned = ""
longness = ""
def __init__(self, pos, **kwds):
ExprNode.__init__(self, pos, **kwds)
if 'type' not in kwds:
rank = max(1, len(self.longness))
sign = not self.unsigned
self.type = PyrexTypes.modifiers_and_name_to_type[sign, rank, "int"]
def coerce_to(self, dst_type, env):
if self.type is dst_type:
return self
elif dst_type.is_float:
float_value = float(self.value)
return FloatNode(self.pos, value=repr(float_value), constant_result=float_value)
node = IntNode(self.pos, value=self.value, constant_result=self.constant_result,
unsigned=self.unsigned, longness=self.longness)
if dst_type.is_numeric and not dst_type.is_complex:
return node
if dst_type.is_pyobject:
node.type = PyrexTypes.py_object_type
# We still need to perform normal coerce_to processing on the
# result, because we might be coercing to an extension type,
# in which case a type test node will be needed.
return ConstNode.coerce_to(node, dst_type, env)
def coerce_to_boolean(self, env):
return IntNode(
self.pos, value=self.value,
type = PyrexTypes.c_bint_type,
unsigned=self.unsigned, longness=self.longness)
def generate_evaluation_code(self, code):
if self.type.is_pyobject:
# pre-allocate a Python version of the number
self.result_code = code.get_py_num(self.value, self.longness)
else:
self.result_code = self.get_constant_c_result_code()
def get_constant_c_result_code(self):
value = self.value
if isinstance(value, basestring) and len(value) > 2:
# must convert C-incompatible Py3 oct/bin notations
if value[1] in 'oO':
value = value[0] + value[2:] # '0o123' => '0123'
elif value[1] in 'bB':
value = int(value[2:], 2)
return str(value) + self.unsigned + self.longness
def calculate_result_code(self):
return self.result_code
def calculate_constant_result(self):
self.constant_result = Utils.str_to_number(self.value)
def compile_time_value(self, denv):
return Utils.str_to_number(self.value)
class FloatNode(ConstNode):
type = PyrexTypes.c_double_type
def calculate_constant_result(self):
self.constant_result = float(self.value)
def compile_time_value(self, denv):
return float(self.value)
def calculate_result_code(self):
strval = self.value
assert isinstance(strval, (str, unicode))
cmpval = repr(float(strval))
if cmpval == 'nan':
return "(Py_HUGE_VAL * 0)"
elif cmpval == 'inf':
return "Py_HUGE_VAL"
elif cmpval == '-inf':
return "(-Py_HUGE_VAL)"
else:
return strval
class BytesNode(ConstNode):
# A char* or bytes literal
#
# value BytesLiteral
type = PyrexTypes.c_char_ptr_type
def compile_time_value(self, denv):
return self.value
def analyse_as_type(self, env):
type = PyrexTypes.parse_basic_type(self.value)
if type is not None:
return type
from TreeFragment import TreeFragment
pos = (self.pos[0], self.pos[1], self.pos[2]-7)
declaration = TreeFragment(u"sizeof(%s)" % self.value, name=pos[0].filename, initial_pos=pos)
sizeof_node = declaration.root.stats[0].expr
sizeof_node.analyse_types(env)
if isinstance(sizeof_node, SizeofTypeNode):
return sizeof_node.arg_type
def can_coerce_to_char_literal(self):
return len(self.value) == 1
def coerce_to_boolean(self, env):
# This is special because we start off as a C char*. Testing
# that for truth directly would yield the wrong result.
return BoolNode(self.pos, value=bool(self.value))
def coerce_to(self, dst_type, env):
if dst_type.is_int:
if not self.can_coerce_to_char_literal():
error(self.pos, "Only single-character string literals can be coerced into ints.")
return self
if dst_type is PyrexTypes.c_py_unicode_type:
error(self.pos, "Bytes literals cannot coerce to Py_UNICODE, use a unicode literal instead.")
return self
return CharNode(self.pos, value=self.value)
node = BytesNode(self.pos, value=self.value)
if dst_type == PyrexTypes.c_char_ptr_type:
node.type = PyrexTypes.c_char_ptr_type
return node
elif dst_type == PyrexTypes.c_uchar_ptr_type:
node.type = PyrexTypes.c_char_ptr_type
return CastNode(node, PyrexTypes.c_uchar_ptr_type)
if not self.type.is_pyobject:
if dst_type in (py_object_type, Builtin.bytes_type):
node.type = Builtin.bytes_type
elif dst_type.is_pyobject:
self.fail_assignment(dst_type)
return self
elif dst_type.is_pyobject and dst_type is not py_object_type:
self.check_for_coercion_error(dst_type, fail=True)
return node
# We still need to perform normal coerce_to processing on the
# result, because we might be coercing to an extension type,
# in which case a type test node will be needed.
return ConstNode.coerce_to(node, dst_type, env)
def as_py_string_node(self, env):
# Return a new BytesNode with the same value as this node
# but whose type is a Python type instead of a C type.
return BytesNode(self.pos, value = self.value, type = Builtin.bytes_type)
def generate_evaluation_code(self, code):
if self.type.is_pyobject:
self.result_code = code.get_py_string_const(self.value)
else:
self.result_code = code.get_string_const(self.value)
def get_constant_c_result_code(self):
return None # FIXME
def calculate_result_code(self):
return self.result_code
class UnicodeNode(PyConstNode):
# A Python unicode object
#
# value EncodedString
# bytes_value BytesLiteral the literal parsed as bytes string ('-3' unicode literals only)
bytes_value = None
type = unicode_type
def coerce_to(self, dst_type, env):
if dst_type is self.type:
pass
elif dst_type is PyrexTypes.c_py_unicode_type:
if not self.can_coerce_to_char_literal():
error(self.pos, "Only single-character Unicode string literals can be coerced into Py_UNICODE.")
return self
int_value = ord(self.value)
return IntNode(self.pos, value=int_value, constant_result=int_value)
elif not dst_type.is_pyobject:
if dst_type.is_string and self.bytes_value is not None:
# special case: '-3' enforced unicode literal used in a C char* context
return BytesNode(self.pos, value=self.bytes_value).coerce_to(dst_type, env)
error(self.pos, "Unicode literals do not support coercion to C types other than Py_UNICODE.")
elif dst_type is not py_object_type:
if not self.check_for_coercion_error(dst_type):
self.fail_assignment(dst_type)
return self
def can_coerce_to_char_literal(self):
return len(self.value) == 1
def contains_surrogates(self):
# Check if the unicode string contains surrogate code points
# on a CPython platform with wide (UCS-4) or narrow (UTF-16)
# Unicode, i.e. characters that would be spelled as two
# separate code units on a narrow platform.
for c in map(ord, self.value):
if c > 65535: # can only happen on wide platforms
return True
# We only look for the first code unit (D800-DBFF) of a
# surrogate pair - if we find one, the other one
# (DC00-DFFF) is likely there, too. If we don't find it,
# any second code unit cannot make for a surrogate pair by
# itself.
if c >= 0xD800 and c <= 0xDBFF:
return True
return False
def generate_evaluation_code(self, code):
self.result_code = code.get_py_string_const(self.value)
def calculate_result_code(self):
return self.result_code
def compile_time_value(self, env):
return self.value
class StringNode(PyConstNode):
# A Python str object, i.e. a byte string in Python 2.x and a
# unicode string in Python 3.x
#
# value BytesLiteral
# unicode_value EncodedString
# is_identifier boolean
type = str_type
is_identifier = None
unicode_value = None
def coerce_to(self, dst_type, env):
if dst_type is not py_object_type and not str_type.subtype_of(dst_type):
# if dst_type is Builtin.bytes_type:
# # special case: bytes = 'str literal'
# return BytesNode(self.pos, value=self.value)
if not dst_type.is_pyobject:
return BytesNode(self.pos, value=self.value).coerce_to(dst_type, env)
self.check_for_coercion_error(dst_type, fail=True)
# this will be a unicode string in Py3, so make sure we can decode it
if self.value.encoding:
encoding = self.value.encoding
try:
self.value.decode(encoding)
except UnicodeDecodeError:
error(self.pos, "String decoding as '%s' failed. Consider using a byte string or unicode string explicitly, or adjust the source code encoding." % encoding)
return self
def can_coerce_to_char_literal(self):
return not self.is_identifier and len(self.value) == 1
def generate_evaluation_code(self, code):
self.result_code = code.get_py_string_const(
self.value, identifier=self.is_identifier, is_str=True)
def get_constant_c_result_code(self):
return None
def calculate_result_code(self):
return self.result_code
def compile_time_value(self, env):
return self.value
class IdentifierStringNode(StringNode):
# A special str value that represents an identifier (bytes in Py2,
# unicode in Py3).
is_identifier = True
class LongNode(AtomicExprNode):
# Python long integer literal
#
# value string
type = py_object_type
def calculate_constant_result(self):
self.constant_result = Utils.str_to_number(self.value)
def compile_time_value(self, denv):
return Utils.str_to_number(self.value)
def analyse_types(self, env):
self.is_temp = 1
def may_be_none(self):
return False
gil_message = "Constructing Python long int"
def generate_result_code(self, code):
code.putln(
'%s = PyLong_FromString((char *)"%s", 0, 0); %s' % (
self.result(),
self.value,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
class ImagNode(AtomicExprNode):
# Imaginary number literal
#
# value float imaginary part
type = PyrexTypes.c_double_complex_type
def calculate_constant_result(self):
self.constant_result = complex(0.0, self.value)
def compile_time_value(self, denv):
return complex(0.0, self.value)
def analyse_types(self, env):
self.type.create_declaration_utility_code(env)
def may_be_none(self):
return False
def coerce_to(self, dst_type, env):
if self.type is dst_type:
return self
node = ImagNode(self.pos, value=self.value)
if dst_type.is_pyobject:
node.is_temp = 1
node.type = PyrexTypes.py_object_type
# We still need to perform normal coerce_to processing on the
# result, because we might be coercing to an extension type,
# in which case a type test node will be needed.
return AtomicExprNode.coerce_to(node, dst_type, env)
gil_message = "Constructing complex number"
def calculate_result_code(self):
if self.type.is_pyobject:
return self.result()
else:
return "%s(0, %r)" % (self.type.from_parts, float(self.value))
def generate_result_code(self, code):
if self.type.is_pyobject:
code.putln(
"%s = PyComplex_FromDoubles(0.0, %r); %s" % (
self.result(),
float(self.value),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
class NewExprNode(AtomicExprNode):
# C++ new statement
#
# cppclass node c++ class to create
type = None
def infer_type(self, env):
type = self.cppclass.analyse_as_type(env)
if type is None or not type.is_cpp_class:
error(self.pos, "new operator can only be applied to a C++ class")
self.type = error_type
return
self.cpp_check(env)
constructor = type.scope.lookup(u'')
if constructor is None:
return_type = PyrexTypes.CFuncType(type, [])
return_type = PyrexTypes.CPtrType(return_type)
type.scope.declare_cfunction(u'', return_type, self.pos)
constructor = type.scope.lookup(u'')
self.class_type = type
self.entry = constructor
self.type = constructor.type
return self.type
def analyse_types(self, env):
if self.type is None:
self.infer_type(env)
def may_be_none(self):
return False
def generate_result_code(self, code):
pass
def calculate_result_code(self):
return "new " + self.class_type.declaration_code("")
class NameNode(AtomicExprNode):
# Reference to a local or global variable name.
#
# name string Python name of the variable
# entry Entry Symbol table entry
# type_entry Entry For extension type names, the original type entry
is_name = True
is_cython_module = False
cython_attribute = None
lhs_of_first_assignment = False
is_used_as_rvalue = 0
entry = None
type_entry = None
def create_analysed_rvalue(pos, env, entry):
node = NameNode(pos)
node.analyse_types(env, entry=entry)
return node
def as_cython_attribute(self):
return self.cython_attribute
create_analysed_rvalue = staticmethod(create_analysed_rvalue)
def type_dependencies(self, env):
if self.entry is None:
self.entry = env.lookup(self.name)
if self.entry is not None and self.entry.type.is_unspecified:
return (self.entry,)
else:
return ()
def infer_type(self, env):
if self.entry is None:
self.entry = env.lookup(self.name)
if self.entry is None:
return py_object_type
elif (self.entry.type.is_extension_type or self.entry.type.is_builtin_type) and \
self.name == self.entry.type.name:
# Unfortunately the type attribute of type objects
# is used for the pointer to the type they represent.
return type_type
else:
return self.entry.type
def compile_time_value(self, denv):
try:
return denv.lookup(self.name)
except KeyError:
error(self.pos, "Compile-time name '%s' not defined" % self.name)
def get_constant_c_result_code(self):
if not self.entry or self.entry.type.is_pyobject:
return None
return self.entry.cname
def coerce_to(self, dst_type, env):
# If coercing to a generic pyobject and this is a builtin
# C function with a Python equivalent, manufacture a NameNode
# referring to the Python builtin.
#print "NameNode.coerce_to:", self.name, dst_type ###
if dst_type is py_object_type:
entry = self.entry
if entry and entry.is_cfunction:
var_entry = entry.as_variable
if var_entry:
if var_entry.is_builtin and Options.cache_builtins:
var_entry = env.declare_builtin(var_entry.name, self.pos)
node = NameNode(self.pos, name = self.name)
node.entry = var_entry
node.analyse_rvalue_entry(env)
return node
return super(NameNode, self).coerce_to(dst_type, env)
def analyse_as_module(self, env):
# Try to interpret this as a reference to a cimported module.
# Returns the module scope, or None.
entry = self.entry
if not entry:
entry = env.lookup(self.name)
if entry and entry.as_module:
return entry.as_module
return None
def analyse_as_type(self, env):
if self.cython_attribute:
type = PyrexTypes.parse_basic_type(self.cython_attribute)
else:
type = PyrexTypes.parse_basic_type(self.name)
if type:
return type
entry = self.entry
if not entry:
entry = env.lookup(self.name)
if entry and entry.is_type:
return entry.type
else:
return None
def analyse_as_extension_type(self, env):
# Try to interpret this as a reference to an extension type.
# Returns the extension type, or None.
entry = self.entry
if not entry:
entry = env.lookup(self.name)
if entry and entry.is_type and entry.type.is_extension_type:
return entry.type
else:
return None
def analyse_target_declaration(self, env):
if not self.entry:
self.entry = env.lookup_here(self.name)
if not self.entry:
if env.directives['warn.undeclared']:
warning(self.pos, "implicit declaration of '%s'" % self.name, 1)
if env.directives['infer_types'] != False:
type = unspecified_type
else:
type = py_object_type
self.entry = env.declare_var(self.name, type, self.pos)
env.control_flow.set_state(self.pos, (self.name, 'initialized'), True)
env.control_flow.set_state(self.pos, (self.name, 'source'), 'assignment')
if self.entry.is_declared_generic:
self.result_ctype = py_object_type
def analyse_types(self, env):
if self.entry is None:
self.entry = env.lookup(self.name)
if not self.entry:
self.entry = env.declare_builtin(self.name, self.pos)
if not self.entry:
self.type = PyrexTypes.error_type
return
entry = self.entry
if entry:
entry.used = 1
if entry.type.is_buffer:
import Buffer
Buffer.used_buffer_aux_vars(entry)
if entry.utility_code:
env.use_utility_code(entry.utility_code)
self.analyse_rvalue_entry(env)
def analyse_target_types(self, env):
self.analyse_entry(env)
if not self.is_lvalue():
error(self.pos, "Assignment to non-lvalue '%s'"
% self.name)
self.type = PyrexTypes.error_type
self.entry.used = 1
if self.entry.type.is_buffer:
import Buffer
Buffer.used_buffer_aux_vars(self.entry)
def analyse_rvalue_entry(self, env):
#print "NameNode.analyse_rvalue_entry:", self.name ###
#print "Entry:", self.entry.__dict__ ###
self.analyse_entry(env)
entry = self.entry
if entry.is_declared_generic:
self.result_ctype = py_object_type
if entry.is_pyglobal or entry.is_builtin:
if Options.cache_builtins and entry.is_builtin:
self.is_temp = 0
else:
self.is_temp = 1
env.use_utility_code(get_name_interned_utility_code)
self.is_used_as_rvalue = 1
def nogil_check(self, env):
if self.is_used_as_rvalue:
entry = self.entry
if entry.is_builtin:
# if not Options.cache_builtins: # cached builtins are ok
self.gil_error()
elif entry.is_pyglobal:
self.gil_error()
gil_message = "Accessing Python global or builtin"
def analyse_entry(self, env):
#print "NameNode.analyse_entry:", self.name ###
self.check_identifier_kind()
entry = self.entry
type = entry.type
self.type = type
def check_identifier_kind(self):
# Check that this is an appropriate kind of name for use in an
# expression. Also finds the variable entry associated with
# an extension type.
entry = self.entry
if entry.is_type and entry.type.is_extension_type:
self.type_entry = entry
if not (entry.is_const or entry.is_variable
or entry.is_builtin or entry.is_cfunction
or entry.is_cpp_class):
if self.entry.as_variable:
self.entry = self.entry.as_variable
else:
error(self.pos,
"'%s' is not a constant, variable or function identifier" % self.name)
def is_simple(self):
# If it's not a C variable, it'll be in a temp.
return 1
def calculate_target_results(self, env):
pass
def check_const(self):
entry = self.entry
if entry is not None and not (entry.is_const or entry.is_cfunction or entry.is_builtin):
self.not_const()
return False
return True
def check_const_addr(self):
entry = self.entry
if not (entry.is_cglobal or entry.is_cfunction or entry.is_builtin):
self.addr_not_const()
return False
return True
def is_lvalue(self):
return self.entry.is_variable and \
not self.entry.type.is_array and \
not self.entry.is_readonly
def is_ephemeral(self):
# Name nodes are never ephemeral, even if the
# result is in a temporary.
return 0
def calculate_result_code(self):
entry = self.entry
if not entry:
return "" # There was an error earlier
return entry.cname
def generate_result_code(self, code):
assert hasattr(self, 'entry')
entry = self.entry
if entry is None:
return # There was an error earlier
if entry.is_builtin and Options.cache_builtins:
return # Lookup already cached
elif entry.is_pyglobal or entry.is_builtin:
assert entry.type.is_pyobject, "Python global or builtin not a Python object"
interned_cname = code.intern_identifier(self.entry.name)
if entry.is_builtin:
namespace = Naming.builtins_cname
else: # entry.is_pyglobal
namespace = entry.scope.namespace_cname
code.globalstate.use_utility_code(get_name_interned_utility_code)
code.putln(
'%s = __Pyx_GetName(%s, %s); %s' % (
self.result(),
namespace,
interned_cname,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
elif entry.is_local and False:
# control flow not good enough yet
assigned = entry.scope.control_flow.get_state((entry.name, 'initialized'), self.pos)
if assigned is False:
error(self.pos, "local variable '%s' referenced before assignment" % entry.name)
elif not Options.init_local_none and assigned is None:
code.putln('if (%s == 0) { PyErr_SetString(PyExc_UnboundLocalError, "%s"); %s }' %
(entry.cname, entry.name, code.error_goto(self.pos)))
entry.scope.control_flow.set_state(self.pos, (entry.name, 'initialized'), True)
def generate_assignment_code(self, rhs, code):
#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):
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.
# We use this to access class->tp_dict if necessary.
if entry.is_pyglobal:
assert entry.type.is_pyobject, "Python global or builtin not a Python object"
interned_cname = code.intern_identifier(self.entry.name)
namespace = self.entry.scope.namespace_cname
if entry.is_member:
# if the entry is a member we have to cheat: SetAttr does not work
# on types, so we create a descriptor which is then added to tp_dict
code.put_error_if_neg(self.pos,
'PyDict_SetItem(%s->tp_dict, %s, %s)' % (
namespace,
interned_cname,
rhs.py_result()))
rhs.generate_disposal_code(code)
rhs.free_temps(code)
# in Py2.6+, we need to invalidate the method cache
code.putln("PyType_Modified(%s);" %
entry.scope.parent_type.typeptr_cname)
else:
code.put_error_if_neg(self.pos,
'PyObject_SetAttr(%s, %s, %s)' % (
namespace,
interned_cname,
rhs.py_result()))
if debug_disposal_code:
print("NameNode.generate_assignment_code:")
print("...generating disposal code for %s" % rhs)
rhs.generate_disposal_code(code)
rhs.free_temps(code)
else:
if self.type.is_buffer:
# Generate code for doing the buffer release/acquisition.
# This might raise an exception in which case the assignment (done
# below) will not happen.
#
# The reason this is not in a typetest-like node is because the
# variables that the acquired buffer info is stored to is allocated
# per entry and coupled with it.
self.generate_acquire_buffer(rhs, code)
if self.type.is_pyobject:
#print "NameNode.generate_assignment_code: to", self.name ###
#print "...from", rhs ###
#print "...LHS type", self.type, "ctype", self.ctype() ###
#print "...RHS type", rhs.type, "ctype", rhs.ctype() ###
if self.use_managed_ref:
rhs.make_owned_reference(code)
if entry.is_cglobal:
code.put_gotref(self.py_result())
if not self.lhs_of_first_assignment:
if entry.is_local and not Options.init_local_none:
initialized = entry.scope.control_flow.get_state((entry.name, 'initialized'), self.pos)
if initialized is True:
code.put_decref(self.result(), self.ctype())
elif initialized is None:
code.put_xdecref(self.result(), self.ctype())
else:
code.put_decref(self.result(), self.ctype())
if entry.is_cglobal:
code.put_giveref(rhs.py_result())
code.putln('%s = %s;' % (self.result(),
rhs.result_as(self.ctype())))
if debug_disposal_code:
print("NameNode.generate_assignment_code:")
print("...generating post-assignment code for %s" % rhs)
rhs.generate_post_assignment_code(code)
rhs.free_temps(code)
def generate_acquire_buffer(self, rhs, code):
# rhstmp is only used in case the rhs is a complicated expression leading to
# the object, to avoid repeating the same C expression for every reference
# to the rhs. It does NOT hold a reference.
pretty_rhs = isinstance(rhs, NameNode) or rhs.is_temp
if pretty_rhs:
rhstmp = rhs.result_as(self.ctype())
else:
rhstmp = code.funcstate.allocate_temp(self.entry.type, manage_ref=False)
code.putln('%s = %s;' % (rhstmp, rhs.result_as(self.ctype())))
buffer_aux = self.entry.buffer_aux
bufstruct = buffer_aux.buffer_info_var.cname
import Buffer
Buffer.put_assign_to_buffer(self.result(), rhstmp, buffer_aux, self.entry.type,
is_initialized=not self.lhs_of_first_assignment,
pos=self.pos, code=code)
if not pretty_rhs:
code.putln("%s = 0;" % rhstmp)
code.funcstate.release_temp(rhstmp)
def generate_deletion_code(self, code):
if self.entry is None:
return # There was an error earlier
if not self.entry.is_pyglobal:
error(self.pos, "Deletion of local or C global name not supported")
return
code.put_error_if_neg(self.pos,
'__Pyx_DelAttrString(%s, "%s")' % (
Naming.module_cname,
self.entry.name))
def annotate(self, code):
if hasattr(self, 'is_called') and self.is_called:
pos = (self.pos[0], self.pos[1], self.pos[2] - len(self.name) - 1)
if self.type.is_pyobject:
code.annotate(pos, AnnotationItem('py_call', 'python function', size=len(self.name)))
else:
code.annotate(pos, AnnotationItem('c_call', 'c function', size=len(self.name)))
class BackquoteNode(ExprNode):
# `expr`
#
# arg ExprNode
type = py_object_type
subexprs = ['arg']
def analyse_types(self, env):
self.arg.analyse_types(env)
self.arg = self.arg.coerce_to_pyobject(env)
self.is_temp = 1
gil_message = "Backquote expression"
def calculate_constant_result(self):
self.constant_result = repr(self.arg.constant_result)
def generate_result_code(self, code):
code.putln(
"%s = PyObject_Repr(%s); %s" % (
self.result(),
self.arg.py_result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
class ImportNode(ExprNode):
# Used as part of import statement implementation.
# Implements result =
# __import__(module_name, globals(), None, name_list)
#
# module_name StringNode dotted name of module
# name_list ListNode or None list of names to be imported
type = py_object_type
subexprs = ['module_name', 'name_list']
def analyse_types(self, env):
self.module_name.analyse_types(env)
self.module_name = self.module_name.coerce_to_pyobject(env)
if self.name_list:
self.name_list.analyse_types(env)
self.name_list.coerce_to_pyobject(env)
self.is_temp = 1
env.use_utility_code(import_utility_code)
gil_message = "Python import"
def generate_result_code(self, code):
if self.name_list:
name_list_code = self.name_list.py_result()
else:
name_list_code = "0"
code.putln(
"%s = __Pyx_Import(%s, %s); %s" % (
self.result(),
self.module_name.py_result(),
name_list_code,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
class IteratorNode(ExprNode):
# Used as part of for statement implementation.
#
# allocate_counter_temp/release_counter_temp needs to be called
# by parent (ForInStatNode)
#
# Implements result = iter(sequence)
#
# sequence ExprNode
type = py_object_type
subexprs = ['sequence']
def analyse_types(self, env):
self.sequence.analyse_types(env)
if (self.sequence.type.is_array or self.sequence.type.is_ptr) and \
not self.sequence.type.is_string:
# C array iteration will be transformed later on
self.type = self.sequence.type
else:
self.sequence = self.sequence.coerce_to_pyobject(env)
self.is_temp = 1
gil_message = "Iterating over Python object"
def allocate_counter_temp(self, code):
self.counter_cname = code.funcstate.allocate_temp(
PyrexTypes.c_py_ssize_t_type, manage_ref=False)
def release_counter_temp(self, code):
code.funcstate.release_temp(self.counter_cname)
def generate_result_code(self, code):
if self.sequence.type.is_array or self.sequence.type.is_ptr:
raise InternalError("for in carray slice not transformed")
is_builtin_sequence = self.sequence.type is list_type or \
self.sequence.type is tuple_type
may_be_a_sequence = is_builtin_sequence or not self.sequence.type.is_builtin_type
if is_builtin_sequence:
code.putln(
"if (likely(%s != Py_None)) {" % self.sequence.py_result())
elif may_be_a_sequence:
code.putln(
"if (PyList_CheckExact(%s) || PyTuple_CheckExact(%s)) {" % (
self.sequence.py_result(),
self.sequence.py_result()))
if may_be_a_sequence:
code.putln(
"%s = 0; %s = %s; __Pyx_INCREF(%s);" % (
self.counter_cname,
self.result(),
self.sequence.py_result(),
self.result()))
code.putln("} else {")
if is_builtin_sequence:
code.putln(
'PyErr_SetString(PyExc_TypeError, "\'NoneType\' object is not iterable"); %s' %
code.error_goto(self.pos))
else:
code.putln("%s = -1; %s = PyObject_GetIter(%s); %s" % (
self.counter_cname,
self.result(),
self.sequence.py_result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
if may_be_a_sequence:
code.putln("}")
class NextNode(AtomicExprNode):
# Used as part of for statement implementation.
# Implements result = iterator.next()
# Created during analyse_types phase.
# The iterator is not owned by this node.
#
# iterator ExprNode
type = py_object_type
def __init__(self, iterator, env):
self.pos = iterator.pos
self.iterator = iterator
if iterator.type.is_ptr or iterator.type.is_array:
self.type = iterator.type.base_type
self.is_temp = 1
def generate_result_code(self, code):
sequence_type = self.iterator.sequence.type
if sequence_type is list_type:
type_checks = [(list_type, "List")]
elif sequence_type is tuple_type:
type_checks = [(tuple_type, "Tuple")]
elif not sequence_type.is_builtin_type:
type_checks = [(list_type, "List"), (tuple_type, "Tuple")]
else:
type_checks = []
for py_type, prefix in type_checks:
if len(type_checks) > 1:
code.putln(
"if (likely(Py%s_CheckExact(%s))) {" % (
prefix, self.iterator.py_result()))
code.putln(
"if (%s >= Py%s_GET_SIZE(%s)) break;" % (
self.iterator.counter_cname,
prefix,
self.iterator.py_result()))
code.putln(
"%s = Py%s_GET_ITEM(%s, %s); __Pyx_INCREF(%s); %s++;" % (
self.result(),
prefix,
self.iterator.py_result(),
self.iterator.counter_cname,
self.result(),
self.iterator.counter_cname))
if len(type_checks) > 1:
code.put("} else ")
if len(type_checks) == 1:
return
code.putln("{")
code.putln(
"%s = PyIter_Next(%s);" % (
self.result(),
self.iterator.py_result()))
code.putln(
"if (!%s) {" %
self.result())
code.putln(code.error_goto_if_PyErr(self.pos))
code.putln("break;")
code.putln("}")
code.put_gotref(self.py_result())
code.putln("}")
class ExcValueNode(AtomicExprNode):
# Node created during analyse_types phase
# of an ExceptClauseNode to fetch the current
# exception value.
type = py_object_type
def __init__(self, pos, env):
ExprNode.__init__(self, pos)
def set_var(self, var):
self.var = var
def calculate_result_code(self):
return self.var
def generate_result_code(self, code):
pass
def analyse_types(self, env):
pass
class TempNode(ExprNode):
# Node created during analyse_types phase
# of some nodes to hold a temporary value.
#
# Note: One must call "allocate" and "release" on
# the node during code generation to get/release the temp.
# This is because the temp result is often used outside of
# the regular cycle.
subexprs = []
def __init__(self, pos, type, env):
ExprNode.__init__(self, pos)
self.type = type
if type.is_pyobject:
self.result_ctype = py_object_type
self.is_temp = 1
def analyse_types(self, env):
return self.type
def generate_result_code(self, code):
pass
def allocate(self, code):
self.temp_cname = code.funcstate.allocate_temp(self.type, manage_ref=True)
def release(self, code):
code.funcstate.release_temp(self.temp_cname)
self.temp_cname = None
def result(self):
try:
return self.temp_cname
except:
assert False, "Remember to call allocate/release on TempNode"
raise
# Do not participate in normal temp alloc/dealloc:
def allocate_temp_result(self, code):
pass
def release_temp_result(self, code):
pass
class PyTempNode(TempNode):
# TempNode holding a Python value.
def __init__(self, pos, env):
TempNode.__init__(self, pos, PyrexTypes.py_object_type, env)
class RawCNameExprNode(ExprNode):
subexprs = []
def __init__(self, pos, type=None):
self.pos = pos
self.type = type
def analyse_types(self, env):
return self.type
def set_cname(self, cname):
self.cname = cname
def result(self):
return self.cname
def generate_result_code(self, code):
pass
#-------------------------------------------------------------------
#
# Trailer nodes
#
#-------------------------------------------------------------------
class IndexNode(ExprNode):
# Sequence indexing.
#
# base ExprNode
# index ExprNode
# indices [ExprNode]
# is_buffer_access boolean Whether this is a buffer access.
#
# indices is used on buffer access, index on non-buffer access.
# The former contains a clean list of index parameters, the
# latter whatever Python object is needed for index access.
subexprs = ['base', 'index', 'indices']
indices = None
def __init__(self, pos, index, *args, **kw):
ExprNode.__init__(self, pos, index=index, *args, **kw)
self._index = index
def calculate_constant_result(self):
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, e:
self.compile_time_value_error(e)
def is_ephemeral(self):
return self.base.is_ephemeral()
def analyse_target_declaration(self, env):
pass
def analyse_as_type(self, env):
base_type = self.base.analyse_as_type(env)
if base_type and not base_type.is_pyobject:
if base_type.is_cpp_class:
if isinstance(self.index, TupleNode):
template_values = self.index.args
else:
template_values = [self.index]
import Nodes
type_node = Nodes.TemplatedTypeNode(
pos = self.pos,
positional_args = template_values,
keyword_args = None)
return type_node.analyse(env, base_type = base_type)
else:
return PyrexTypes.CArrayType(base_type, int(self.index.compile_time_value(env)))
return None
def type_dependencies(self, env):
return self.base.type_dependencies(env)
def infer_type(self, env):
base_type = self.base.infer_type(env)
if isinstance(self.index, SliceNode):
# slicing!
if base_type.is_string:
# sliced C strings must coerce to Python
return bytes_type
elif base_type in (unicode_type, bytes_type, str_type, list_type, tuple_type):
# slicing these returns the same type
return base_type
else:
# TODO: Handle buffers (hopefully without too much redundancy).
return py_object_type
index_type = self.index.infer_type(env)
if index_type and index_type.is_int or isinstance(self.index, (IntNode, LongNode)):
# indexing!
if base_type is unicode_type:
# Py_UNICODE will automatically coerce to a unicode string
# if required, so this is safe. We only infer Py_UNICODE
# when the index is a C integer type. Otherwise, we may
# need to use normal Python item access, in which case
# it's faster to return the one-char unicode string than
# to receive it, throw it away, and potentially rebuild it
# on a subsequent PyObject coercion.
return PyrexTypes.c_py_unicode_type
elif isinstance(self.base, BytesNode):
#if env.global_scope().context.language_level >= 3:
# # infering 'char' can be made to work in Python 3 mode
# return PyrexTypes.c_char_type
# Py2/3 return different types on indexing bytes objects
return py_object_type
elif base_type.is_ptr or base_type.is_array:
return base_type.base_type
# may be slicing or indexing, we don't know
if base_type is unicode_type:
# this type always returns its own type on Python indexing/slicing
return base_type
else:
# TODO: Handle buffers (hopefully without too much redundancy).
return py_object_type
def analyse_types(self, env):
self.analyse_base_and_index_types(env, getting = 1)
def analyse_target_types(self, env):
self.analyse_base_and_index_types(env, setting = 1)
def analyse_base_and_index_types(self, env, getting = 0, setting = 0):
# Note: This might be cleaned up by having IndexNode
# parsed in a saner way and only construct the tuple if
# needed.
# Note that this function must leave IndexNode in a cloneable state.
# For buffers, self.index is packed out on the initial analysis, and
# when cloning self.indices is copied.
self.is_buffer_access = False
self.base.analyse_types(env)
if self.base.type.is_error:
# Do not visit child tree if base is undeclared to avoid confusing
# error messages
self.type = PyrexTypes.error_type
return
is_slice = isinstance(self.index, SliceNode)
# Potentially overflowing index value.
if not is_slice and isinstance(self.index, IntNode) and Utils.long_literal(self.index.value):
self.index = self.index.coerce_to_pyobject(env)
# Handle the case where base is a literal char* (and we expect a string, not an int)
if isinstance(self.base, BytesNode) or is_slice:
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)
skip_child_analysis = False
buffer_access = False
if self.base.type.is_buffer:
assert hasattr(self.base, "entry") # Must be a NameNode-like node
if self.indices:
indices = self.indices
else:
if isinstance(self.index, TupleNode):
indices = self.index.args
else:
indices = [self.index]
if len(indices) == self.base.type.ndim:
buffer_access = True
skip_child_analysis = True
for x in indices:
x.analyse_types(env)
if not x.type.is_int:
buffer_access = False
# On cloning, indices is cloned. Otherwise, unpack index into indices
assert not (buffer_access and isinstance(self.index, CloneNode))
if buffer_access:
self.indices = indices
self.index = None
self.type = self.base.type.dtype
self.is_buffer_access = True
self.buffer_type = self.base.entry.type
if getting and self.type.is_pyobject:
self.is_temp = True
if setting:
if not self.base.entry.type.writable:
error(self.pos, "Writing to readonly buffer")
else:
self.base.entry.buffer_aux.writable_needed = True
else:
base_type = self.base.type
if isinstance(self.index, TupleNode):
self.index.analyse_types(env, skip_children=skip_child_analysis)
elif not skip_child_analysis:
self.index.analyse_types(env)
self.original_index_type = self.index.type
if base_type is PyrexTypes.c_py_unicode_type:
# we infer Py_UNICODE for unicode strings in some
# cases, but indexing must still work for them
if self.index.constant_result in (0, -1):
# FIXME: we know that this node is redundant -
# currently, this needs to get handled in Optimize.py
pass
self.base = self.base.coerce_to_pyobject(env)
base_type = self.base.type
if base_type.is_pyobject:
if self.index.type.is_int:
if (not setting
and (base_type in (list_type, tuple_type, unicode_type))
and (not self.index.type.signed or isinstance(self.index, IntNode) and int(self.index.value) >= 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)
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 will automatically coerce to a unicode string
# if required, so this is fast and safe
self.type = PyrexTypes.c_py_unicode_type
elif is_slice and base_type in (bytes_type, str_type, unicode_type, list_type, tuple_type):
self.type = base_type
else:
self.type = py_object_type
else:
if base_type.is_ptr or base_type.is_array:
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)
elif base_type.is_cpp_class:
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 = ""
return
func_type = function.type
if func_type.is_ptr:
func_type = func_type.base_type
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)
else:
error(self.pos,
"Attempting to index non-array type '%s'" %
base_type)
self.type = PyrexTypes.error_type
gil_message = "Indexing Python object"
def nogil_check(self, env):
if self.is_buffer_access:
if env.directives['boundscheck']:
error(self.pos, "Cannot check buffer index bounds without gil; use boundscheck(False) directive")
return
elif self.type.is_pyobject:
error(self.pos, "Cannot access buffer with object dtype without gil")
return
super(IndexNode, self).nogil_check(env)
def check_const_addr(self):
return self.base.check_const_addr() and self.index.check_const()
def is_lvalue(self):
return 1
def calculate_result_code(self):
if self.is_buffer_access:
return "(*%s)" % self.buffer_ptr_code
elif self.base.type is list_type:
return "PyList_GET_ITEM(%s, %s)" % (self.base.result(), self.index.result())
elif self.base.type is tuple_type:
return "PyTuple_GET_ITEM(%s, %s)" % (self.base.result(), self.index.result())
elif self.base.type is unicode_type and self.type is PyrexTypes.c_py_unicode_type:
return "PyUnicode_AS_UNICODE(%s)[%s]" % (self.base.result(), self.index.result())
elif (self.type.is_ptr or self.type.is_array) and self.type == self.base.type:
error(self.pos, "Invalid use of pointer slice")
else:
return "(%s[%s])" % (
self.base.result(), self.index.result())
def extra_index_params(self):
if self.index.type.is_int:
if self.original_index_type.signed:
size_adjustment = ""
else:
size_adjustment = "+1"
return ", sizeof(%s)%s, %s" % (self.original_index_type.declaration_code(""), size_adjustment, self.original_index_type.to_py_function)
else:
return ""
def generate_subexpr_evaluation_code(self, code):
self.base.generate_evaluation_code(code)
if not self.indices:
self.index.generate_evaluation_code(code)
else:
for i in self.indices:
i.generate_evaluation_code(code)
def generate_subexpr_disposal_code(self, code):
self.base.generate_disposal_code(code)
if not self.indices:
self.index.generate_disposal_code(code)
else:
for i in self.indices:
i.generate_disposal_code(code)
def free_subexpr_temps(self, code):
self.base.free_temps(code)
if not self.indices:
self.index.free_temps(code)
else:
for i in self.indices:
i.free_temps(code)
def generate_result_code(self, code):
if self.is_buffer_access:
if code.globalstate.directives['nonecheck']:
self.put_nonecheck(code)
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.
code.putln("%s = *%s;" % (self.result(), self.buffer_ptr_code))
code.putln("__Pyx_INCREF((PyObject*)%s);" % self.result())
elif self.is_temp:
if self.type.is_pyobject:
if self.index.type.is_int:
index_code = self.index.result()
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"
code.globalstate.use_utility_code(getitem_int_utility_code)
else:
index_code = self.index.py_result()
if self.base.type is dict_type:
function = "__Pyx_PyDict_GetItem"
code.globalstate.use_utility_code(getitem_dict_utility_code)
else:
function = "PyObject_GetItem"
code.putln(
"%s = %s(%s, %s%s); if (!%s) %s" % (
self.result(),
function,
self.base.py_result(),
index_code,
self.extra_index_params(),
self.result(),
code.error_goto(self.pos)))
code.put_gotref(self.py_result())
elif self.type is PyrexTypes.c_py_unicode_type and self.base.type is unicode_type:
assert self.index.type.is_int
index_code = self.index.result()
function = "__Pyx_GetItemInt_Unicode"
code.globalstate.use_utility_code(getitem_int_pyunicode_utility_code)
code.putln(
"%s = %s(%s, %s%s); if (unlikely(%s == (Py_UNICODE)-1)) %s;" % (
self.result(),
function,
self.base.py_result(),
index_code,
self.extra_index_params(),
self.result(),
code.error_goto(self.pos)))
def generate_setitem_code(self, value_code, code):
if self.index.type.is_int:
function = "__Pyx_SetItemInt"
index_code = self.index.result()
code.globalstate.use_utility_code(setitem_int_utility_code)
else:
index_code = self.index.py_result()
if self.base.type is dict_type:
function = "PyDict_SetItem"
# It would seem that we could specialized lists/tuples, but that
# shouldn't happen here.
# Both PyList_SetItem PyTuple_SetItem and a Py_ssize_t as input,
# not a PyObject*, and bad conversion here would give the wrong
# exception. Also, tuples are supposed to be immutable, and raise
# TypeErrors when trying to set their entries (PyTuple_SetItem
# is for creating new tuples from).
else:
function = "PyObject_SetItem"
code.putln(
"if (%s(%s, %s, %s%s) < 0) %s" % (
function,
self.base.py_result(),
index_code,
value_code,
self.extra_index_params(),
code.error_goto(self.pos)))
def generate_buffer_setitem_code(self, rhs, code, op=""):
# Used from generate_assignment_code and InPlaceAssignmentNode
if code.globalstate.directives['nonecheck']:
self.put_nonecheck(code)
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(self.buffer_type.buffer_ptr_type, manage_ref=False)
rhs_code = rhs.result()
code.putln("%s = %s;" % (ptr, ptrexpr))
code.put_gotref("*%s" % ptr)
code.putln("__Pyx_DECREF(*%s); __Pyx_INCREF(%s);" % (
ptr, rhs_code
))
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_assignment_code(self, rhs, code):
self.generate_subexpr_evaluation_code(code)
if self.is_buffer_access:
self.generate_buffer_setitem_code(rhs, code)
elif self.type.is_pyobject:
self.generate_setitem_code(rhs.py_result(), code)
else:
code.putln(
"%s = %s;" % (
self.result(), rhs.result()))
self.generate_subexpr_disposal_code(code)
self.free_subexpr_temps(code)
rhs.generate_disposal_code(code)
rhs.free_temps(code)
def generate_deletion_code(self, code):
self.generate_subexpr_evaluation_code(code)
#if self.type.is_pyobject:
if self.index.type.is_int:
function = "__Pyx_DelItemInt"
index_code = self.index.result()
code.globalstate.use_utility_code(delitem_int_utility_code)
else:
index_code = self.index.py_result()
if self.base.type is dict_type:
function = "PyDict_DelItem"
else:
function = "PyObject_DelItem"
code.putln(
"if (%s(%s, %s%s) < 0) %s" % (
function,
self.base.py_result(),
index_code,
self.extra_index_params(),
code.error_goto(self.pos)))
self.generate_subexpr_disposal_code(code)
self.free_subexpr_temps(code)
def buffer_lookup_code(self, code):
# Assign indices to temps
index_temps = [code.funcstate.allocate_temp(i.type, manage_ref=False) for i in self.indices]
for temp, index in zip(index_temps, self.indices):
code.putln("%s = %s;" % (temp, index.result()))
# Generate buffer access code using these temps
import Buffer
# The above could happen because child_attrs is wrong somewhere so that
# options are not propagated.
return Buffer.put_buffer_lookup_code(entry=self.base.entry,
index_signeds=[i.type.signed for i in self.indices],
index_cnames=index_temps,
directives=code.globalstate.directives,
pos=self.pos, code=code)
def put_nonecheck(self, code):
code.globalstate.use_utility_code(raise_noneindex_error_utility_code)
code.putln("if (%s) {" % code.unlikely("%s == Py_None") % self.base.result_as(PyrexTypes.py_object_type))
code.putln("__Pyx_RaiseNoneIndexingError();")
code.putln(code.error_goto(self.pos))
code.putln("}")
class SliceIndexNode(ExprNode):
# 2-element slice indexing
#
# base ExprNode
# start ExprNode or None
# stop ExprNode or None
subexprs = ['base', 'start', 'stop']
def infer_type(self, env):
base_type = self.base.infer_type(env)
if base_type.is_string:
return bytes_type
elif base_type in (bytes_type, str_type, unicode_type,
list_type, tuple_type):
return base_type
return py_object_type
def calculate_constant_result(self):
self.constant_result = self.base.constant_result[
self.start.constant_result : self.stop.constant_result]
def compile_time_value(self, denv):
base = self.base.compile_time_value(denv)
if self.start is None:
start = 0
else:
start = self.start.compile_time_value(denv)
if self.stop is None:
stop = None
else:
stop = self.stop.compile_time_value(denv)
try:
return base[start:stop]
except Exception, e:
self.compile_time_value_error(e)
def analyse_target_declaration(self, env):
pass
def analyse_target_types(self, env):
self.analyse_types(env)
# when assigning, we must accept any Python type
if self.type.is_pyobject:
self.type = py_object_type
def analyse_types(self, env):
self.base.analyse_types(env)
if self.start:
self.start.analyse_types(env)
if self.stop:
self.stop.analyse_types(env)
base_type = self.base.type
if base_type.is_string:
self.type = bytes_type
elif base_type.is_ptr:
self.type = base_type
elif base_type.is_array:
# we need a ptr type here instead of an array type, as
# array types can result in invalid type casts in the C
# code
self.type = PyrexTypes.CPtrType(base_type.base_type)
else:
self.base = self.base.coerce_to_pyobject(env)
self.type = py_object_type
if base_type.is_builtin_type:
# slicing builtin types returns something of the same type
self.type = base_type
c_int = PyrexTypes.c_py_ssize_t_type
if self.start:
self.start = self.start.coerce_to(c_int, env)
if self.stop:
self.stop = self.stop.coerce_to(c_int, env)
self.is_temp = 1
nogil_check = Node.gil_error
gil_message = "Slicing Python object"
def generate_result_code(self, code):
if not self.type.is_pyobject:
error(self.pos,
"Slicing is not currently supported for '%s'." % self.type)
return
if self.base.type.is_string:
if self.stop is None:
code.putln(
"%s = PyBytes_FromString(%s + %s); %s" % (
self.result(),
self.base.result(),
self.start_code(),
code.error_goto_if_null(self.result(), self.pos)))
else:
code.putln(
"%s = PyBytes_FromStringAndSize(%s + %s, %s - %s); %s" % (
self.result(),
self.base.result(),
self.start_code(),
self.stop_code(),
self.start_code(),
code.error_goto_if_null(self.result(), self.pos)))
else:
code.putln(
"%s = PySequence_GetSlice(%s, %s, %s); %s" % (
self.result(),
self.base.py_result(),
self.start_code(),
self.stop_code(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
def generate_assignment_code(self, rhs, code):
self.generate_subexpr_evaluation_code(code)
if self.type.is_pyobject:
code.put_error_if_neg(self.pos,
"PySequence_SetSlice(%s, %s, %s, %s)" % (
self.base.py_result(),
self.start_code(),
self.stop_code(),
rhs.py_result()))
else:
start_offset = ''
if self.start:
start_offset = self.start_code()
if start_offset == '0':
start_offset = ''
else:
start_offset += '+'
if rhs.type.is_array:
array_length = rhs.type.size
self.generate_slice_guard_code(code, array_length)
else:
error(self.pos,
"Slice assignments from pointers are not yet supported.")
# FIXME: fix the array size according to start/stop
array_length = self.base.type.size
for i in range(array_length):
code.putln("%s[%s%s] = %s[%d];" % (
self.base.result(), start_offset, i,
rhs.result(), i))
self.generate_subexpr_disposal_code(code)
self.free_subexpr_temps(code)
rhs.generate_disposal_code(code)
rhs.free_temps(code)
def generate_deletion_code(self, code):
if not self.base.type.is_pyobject:
error(self.pos,
"Deleting slices is only supported for Python types, not '%s'." % self.type)
return
self.generate_subexpr_evaluation_code(code)
code.put_error_if_neg(self.pos,
"PySequence_DelSlice(%s, %s, %s)" % (
self.base.py_result(),
self.start_code(),
self.stop_code()))
self.generate_subexpr_disposal_code(code)
def generate_slice_guard_code(self, code, target_size):
if not self.base.type.is_array:
return
slice_size = self.base.type.size
start = stop = None
if self.stop:
stop = self.stop.result()
try:
stop = int(stop)
if stop < 0:
slice_size = self.base.type.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:
start = self.base.type.size + start
slice_size -= start
start = None
except ValueError:
pass
check = None
if slice_size < 0:
if target_size > 0:
error(self.pos, "Assignment to empty slice.")
elif start is None and stop is None:
# we know the exact slice length
if target_size != slice_size:
error(self.pos, "Assignment to slice of wrong length, expected %d, got %d" % (
slice_size, target_size))
elif start is not None:
if stop is None:
stop = slice_size
check = "(%s)-(%s)" % (stop, start)
else: # stop is not None:
check = stop
if check:
code.putln("if (unlikely((%s) != %d)) {" % (check, target_size))
code.putln('PyErr_Format(PyExc_ValueError, "Assignment to slice of wrong length, expected %%"PY_FORMAT_SIZE_T"d, got %%"PY_FORMAT_SIZE_T"d", (Py_ssize_t)%d, (Py_ssize_t)(%s));' % (
target_size, check))
code.putln(code.error_goto(self.pos))
code.putln("}")
def start_code(self):
if self.start:
return self.start.result()
else:
return "0"
def stop_code(self):
if self.stop:
return self.stop.result()
elif self.base.type.is_array:
return self.base.type.size
else:
return "PY_SSIZE_T_MAX"
def calculate_result_code(self):
# self.result() is not used, but this method must exist
return ""
class SliceNode(ExprNode):
# start:stop:step in subscript list
#
# start ExprNode
# stop ExprNode
# step ExprNode
type = py_object_type
is_temp = 1
def calculate_constant_result(self):
self.constant_result = self.base.constant_result[
self.start.constant_result : \
self.stop.constant_result : \
self.step.constant_result]
def compile_time_value(self, denv):
start = self.start.compile_time_value(denv)
if self.stop is None:
stop = None
else:
stop = self.stop.compile_time_value(denv)
if self.step is None:
step = None
else:
step = self.step.compile_time_value(denv)
try:
return slice(start, stop, step)
except Exception, e:
self.compile_time_value_error(e)
subexprs = ['start', 'stop', 'step']
def analyse_types(self, env):
self.start.analyse_types(env)
self.stop.analyse_types(env)
self.step.analyse_types(env)
self.start = self.start.coerce_to_pyobject(env)
self.stop = self.stop.coerce_to_pyobject(env)
self.step = self.step.coerce_to_pyobject(env)
gil_message = "Constructing Python slice object"
def generate_result_code(self, code):
code.putln(
"%s = PySlice_New(%s, %s, %s); %s" % (
self.result(),
self.start.py_result(),
self.stop.py_result(),
self.step.py_result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
class CallNode(ExprNode):
# allow overriding the default 'may_be_none' behaviour
may_return_none = None
def may_be_none(self):
if self.may_return_none is not None:
return self.may_return_none
return ExprNode.may_be_none(self)
def analyse_as_type_constructor(self, env):
type = self.function.analyse_as_type(env)
if type and type.is_struct_or_union:
args, kwds = self.explicit_args_kwds()
items = []
for arg, member in zip(args, type.scope.var_entries):
items.append(DictItemNode(pos=arg.pos, key=StringNode(pos=arg.pos, value=member.name), value=arg))
if kwds:
items += kwds.key_value_pairs
self.key_value_pairs = items
self.__class__ = DictNode
self.analyse_types(env)
self.coerce_to(type, env)
return True
elif type and type.is_cpp_class:
for arg in self.args:
arg.analyse_types(env)
constructor = type.scope.lookup("")
self.function = RawCNameExprNode(self.function.pos, constructor.type)
self.function.entry = constructor
self.function.set_cname(type.declaration_code(""))
self.analyse_c_function_call(env)
return True
def is_lvalue(self):
return self.type.is_reference
def nogil_check(self, env):
func_type = self.function_type()
if func_type.is_pyobject:
self.gil_error()
elif not getattr(func_type, 'nogil', False):
self.gil_error()
gil_message = "Calling gil-requiring function"
class SimpleCallNode(CallNode):
# Function call without keyword, * or ** args.
#
# function ExprNode
# args [ExprNode]
# arg_tuple ExprNode or None used internally
# self ExprNode or None used internally
# coerced_self ExprNode or None used internally
# wrapper_call bool used internally
# has_optional_args bool used internally
subexprs = ['self', 'coerced_self', 'function', 'args', 'arg_tuple']
self = None
coerced_self = None
arg_tuple = None
wrapper_call = False
has_optional_args = False
def compile_time_value(self, denv):
function = self.function.compile_time_value(denv)
args = [arg.compile_time_value(denv) for arg in self.args]
try:
return function(*args)
except Exception, e:
self.compile_time_value_error(e)
def type_dependencies(self, env):
# TODO: Update when Danilo's C++ code merged in to handle the
# the case of function overloading.
return self.function.type_dependencies(env)
def infer_type(self, env):
function = self.function
func_type = function.infer_type(env)
if isinstance(self.function, NewExprNode):
return PyrexTypes.CPtrType(self.function.class_type)
if func_type.is_ptr:
func_type = func_type.base_type
if func_type.is_cfunction:
return func_type.return_type
elif func_type is type_type:
if function.is_name and function.entry and function.entry.type:
result_type = function.entry.type
if result_type.is_extension_type:
return result_type
elif result_type.is_builtin_type:
if function.entry.name == 'float':
return PyrexTypes.c_double_type
elif function.entry.name in Builtin.types_that_construct_their_instance:
return result_type
return py_object_type
def analyse_as_type(self, env):
attr = self.function.as_cython_attribute()
if attr == 'pointer':
if len(self.args) != 1:
error(self.args.pos, "only one type allowed.")
else:
type = self.args[0].analyse_as_type(env)
if not type:
error(self.args[0].pos, "Unknown type")
else:
return PyrexTypes.CPtrType(type)
def explicit_args_kwds(self):
return self.args, None
def analyse_types(self, env):
if self.analyse_as_type_constructor(env):
return
function = self.function
function.is_called = 1
self.function.analyse_types(env)
if function.is_attribute and function.entry and function.entry.is_cmethod:
# Take ownership of the object from which the attribute
# was obtained, because we need to pass it as 'self'.
self.self = function.obj
function.obj = CloneNode(self.self)
func_type = self.function_type()
if func_type.is_pyobject:
self.arg_tuple = TupleNode(self.pos, args = self.args)
self.arg_tuple.analyse_types(env)
self.args = None
if func_type is Builtin.type_type and function.is_name and \
function.entry and \
function.entry.is_builtin and \
function.entry.name in Builtin.types_that_construct_their_instance:
# calling a builtin type that returns a specific object type
if function.entry.name == 'float':
# the following will come true later on in a transform
self.type = PyrexTypes.c_double_type
self.result_ctype = PyrexTypes.c_double_type
else:
self.type = Builtin.builtin_types[function.entry.name]
self.result_ctype = py_object_type
self.may_return_none = False
elif function.is_name and function.type_entry:
# We are calling an extension type constructor. As
# long as we do not support __new__(), the result type
# is clear
self.type = function.type_entry.type
self.result_ctype = py_object_type
self.may_return_none = False
else:
self.type = py_object_type
self.is_temp = 1
else:
for arg in self.args:
arg.analyse_types(env)
if self.self and func_type.args:
# Coerce 'self' to the type expected by the method.
expected_type = func_type.args[0].type
self.coerced_self = CloneNode(self.self).coerce_to(
expected_type, env)
# Insert coerced 'self' argument into argument list.
self.args.insert(0, self.coerced_self)
self.analyse_c_function_call(env)
def function_type(self):
# Return the type of the function being called, coercing a function
# pointer to a function if necessary.
func_type = self.function.type
if func_type.is_ptr:
func_type = func_type.base_type
return func_type
def analyse_c_function_call(self, env):
if self.function.type is error_type:
self.type = error_type
return
if self.function.type.is_cpp_class:
overloaded_entry = self.function.type.scope.lookup("operator()")
if overloaded_entry is None:
self.type = PyrexTypes.error_type
self.result_code = ""
return
elif hasattr(self.function, 'entry'):
overloaded_entry = self.function.entry
else:
overloaded_entry = None
if overloaded_entry:
entry = PyrexTypes.best_match(self.args, overloaded_entry.all_alternatives(), self.pos)
if not entry:
self.type = PyrexTypes.error_type
self.result_code = ""
return
self.function.entry = entry
self.function.type = entry.type
func_type = self.function_type()
else:
func_type = self.function_type()
if not func_type.is_cfunction:
error(self.pos, "Calling non-function type '%s'" % func_type)
self.type = PyrexTypes.error_type
self.result_code = ""
return
# Check no. of args
max_nargs = len(func_type.args)
expected_nargs = max_nargs - func_type.optional_arg_count
actual_nargs = len(self.args)
if func_type.optional_arg_count and expected_nargs != actual_nargs:
self.has_optional_args = 1
self.is_temp = 1
# Coerce arguments
for i in range(min(max_nargs, actual_nargs)):
formal_type = func_type.args[i].type
self.args[i] = self.args[i].coerce_to(formal_type, env)
for i in range(max_nargs, actual_nargs):
if self.args[i].type.is_pyobject:
error(self.args[i].pos,
"Python object cannot be passed as a varargs parameter")
# Calc result type and code fragment
if isinstance(self.function, NewExprNode):
self.type = PyrexTypes.CPtrType(self.function.class_type)
else:
self.type = func_type.return_type
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:
self.is_temp = 1
# C++ exception handler
if func_type.exception_check == '+':
if func_type.exception_value is None:
env.use_utility_code(cpp_exception_utility_code)
def calculate_result_code(self):
return self.c_call_code()
def c_call_code(self):
func_type = self.function_type()
if self.type is PyrexTypes.error_type or not func_type.is_cfunction:
return ""
formal_args = func_type.args
arg_list_code = []
args = zip(formal_args, self.args)
max_nargs = len(func_type.args)
expected_nargs = max_nargs - func_type.optional_arg_count
actual_nargs = len(self.args)
for formal_arg, actual_arg in args[:expected_nargs]:
arg_code = actual_arg.result_as(formal_arg.type)
arg_list_code.append(arg_code)
if func_type.is_overridable:
arg_list_code.append(str(int(self.wrapper_call or self.function.entry.is_unbound_cmethod)))
if func_type.optional_arg_count:
if expected_nargs == actual_nargs:
optional_args = 'NULL'
else:
optional_args = "&%s" % self.opt_arg_struct
arg_list_code.append(optional_args)
for actual_arg in self.args[len(formal_args):]:
arg_list_code.append(actual_arg.result())
result = "%s(%s)" % (self.function.result(),
', '.join(arg_list_code))
return result
def generate_result_code(self, code):
func_type = self.function_type()
if func_type.is_pyobject:
arg_code = self.arg_tuple.py_result()
code.putln(
"%s = PyObject_Call(%s, %s, NULL); %s" % (
self.result(),
self.function.py_result(),
arg_code,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
elif func_type.is_cfunction:
if self.has_optional_args:
actual_nargs = len(self.args)
expected_nargs = len(func_type.args) - func_type.optional_arg_count
self.opt_arg_struct = code.funcstate.allocate_temp(
func_type.op_arg_struct.base_type, manage_ref=True)
code.putln("%s.%s = %s;" % (
self.opt_arg_struct,
Naming.pyrex_prefix + "n",
len(self.args) - expected_nargs))
args = zip(func_type.args, self.args)
for formal_arg, actual_arg in args[expected_nargs:actual_nargs]:
code.putln("%s.%s = %s;" % (
self.opt_arg_struct,
func_type.opt_arg_cname(formal_arg.name),
actual_arg.result_as(formal_arg.type)))
exc_checks = []
if self.type.is_pyobject and self.is_temp:
exc_checks.append("!%s" % self.result())
else:
exc_val = func_type.exception_value
exc_check = func_type.exception_check
if exc_val is not None:
exc_checks.append("%s == %s" % (self.result(), exc_val))
if exc_check:
exc_checks.append("PyErr_Occurred()")
if self.is_temp or exc_checks:
rhs = self.c_call_code()
if self.result():
lhs = "%s = " % self.result()
if self.is_temp and self.type.is_pyobject:
#return_type = self.type # func_type.return_type
#print "SimpleCallNode.generate_result_code: casting", rhs, \
# "from", return_type, "to pyobject" ###
rhs = typecast(py_object_type, self.type, rhs)
else:
lhs = ""
if func_type.exception_check == '+':
if func_type.exception_value is None:
raise_py_exception = "__Pyx_CppExn2PyErr()"
elif func_type.exception_value.type.is_pyobject:
raise_py_exception = ' try { throw; } catch(const std::exception& exn) { PyErr_SetString(%s, exn.what()); } catch(...) { PyErr_SetNone(%s); }' % (
func_type.exception_value.entry.cname,
func_type.exception_value.entry.cname)
else:
raise_py_exception = '%s(); if (!PyErr_Occurred()) PyErr_SetString(PyExc_RuntimeError , "Error converting c++ exception.")' % func_type.exception_value.entry.cname
code.putln(
"try {%s%s;} catch(...) {%s; %s}" % (
lhs,
rhs,
raise_py_exception,
code.error_goto(self.pos)))
else:
if exc_checks:
goto_error = code.error_goto_if(" && ".join(exc_checks), self.pos)
else:
goto_error = ""
code.putln("%s%s; %s" % (lhs, rhs, goto_error))
if self.type.is_pyobject and self.result():
code.put_gotref(self.py_result())
if self.has_optional_args:
code.funcstate.release_temp(self.opt_arg_struct)
class PythonCapiFunctionNode(ExprNode):
subexprs = []
def __init__(self, pos, py_name, cname, func_type, utility_code = None):
self.pos = pos
self.name = py_name
self.cname = cname
self.type = func_type
self.utility_code = utility_code
def analyse_types(self, env):
pass
def generate_result_code(self, code):
if self.utility_code:
code.globalstate.use_utility_code(self.utility_code)
def calculate_result_code(self):
return self.cname
class PythonCapiCallNode(SimpleCallNode):
# Python C-API Function call (only created in transforms)
# By default, we assume that the call never returns None, as this
# is true for most C-API functions in CPython. If this does not
# apply to a call, set the following to True (or None to inherit
# the default behaviour).
may_return_none = False
def __init__(self, pos, function_name, func_type,
utility_code = None, py_name=None, **kwargs):
self.type = func_type.return_type
self.result_ctype = self.type
self.function = PythonCapiFunctionNode(
pos, py_name, function_name, func_type,
utility_code = utility_code)
# call this last so that we can override the constructed
# attributes above with explicit keyword arguments if required
SimpleCallNode.__init__(self, pos, **kwargs)
class GeneralCallNode(CallNode):
# General Python function call, including keyword,
# * and ** arguments.
#
# function ExprNode
# positional_args ExprNode Tuple of positional arguments
# keyword_args ExprNode or None Dict of keyword arguments
# starstar_arg ExprNode or None Dict of extra keyword args
type = py_object_type
subexprs = ['function', 'positional_args', 'keyword_args', 'starstar_arg']
nogil_check = Node.gil_error
def compile_time_value(self, denv):
function = self.function.compile_time_value(denv)
positional_args = self.positional_args.compile_time_value(denv)
keyword_args = self.keyword_args.compile_time_value(denv)
starstar_arg = self.starstar_arg.compile_time_value(denv)
try:
keyword_args.update(starstar_arg)
return function(*positional_args, **keyword_args)
except Exception, e:
self.compile_time_value_error(e)
def explicit_args_kwds(self):
if self.starstar_arg or not isinstance(self.positional_args, TupleNode):
raise PostParseError(self.pos,
'Compile-time keyword arguments must be explicit.')
return self.positional_args.args, self.keyword_args
def analyse_types(self, env):
if self.analyse_as_type_constructor(env):
return
self.function.analyse_types(env)
self.positional_args.analyse_types(env)
if self.keyword_args:
self.keyword_args.analyse_types(env)
if self.starstar_arg:
self.starstar_arg.analyse_types(env)
if not self.function.type.is_pyobject:
if self.function.type.is_error:
self.type = error_type
return
if hasattr(self.function, 'entry') and not self.function.entry.as_variable:
error(self.pos, "Keyword and starred arguments not allowed in cdef functions.")
else:
self.function = self.function.coerce_to_pyobject(env)
self.positional_args = \
self.positional_args.coerce_to_pyobject(env)
if self.starstar_arg:
self.starstar_arg = \
self.starstar_arg.coerce_to_pyobject(env)
function = self.function
if function.is_name and function.type_entry:
# We are calling an extension type constructor. As long
# as we do not support __new__(), the result type is clear
self.type = function.type_entry.type
self.result_ctype = py_object_type
self.may_return_none = False
else:
self.type = py_object_type
self.is_temp = 1
def generate_result_code(self, code):
if self.type.is_error: return
kwargs_call_function = "PyEval_CallObjectWithKeywords"
if self.keyword_args and self.starstar_arg:
code.put_error_if_neg(self.pos,
"PyDict_Update(%s, %s)" % (
self.keyword_args.py_result(),
self.starstar_arg.py_result()))
keyword_code = self.keyword_args.py_result()
elif self.keyword_args:
keyword_code = self.keyword_args.py_result()
elif self.starstar_arg:
keyword_code = self.starstar_arg.py_result()
if self.starstar_arg.type is not Builtin.dict_type:
# CPython supports calling functions with non-dicts, so do we
code.globalstate.use_utility_code(kwargs_call_utility_code)
kwargs_call_function = "__Pyx_PyEval_CallObjectWithKeywords"
else:
keyword_code = None
if not keyword_code:
call_code = "PyObject_Call(%s, %s, NULL)" % (
self.function.py_result(),
self.positional_args.py_result())
else:
call_code = "%s(%s, %s, %s)" % (
kwargs_call_function,
self.function.py_result(),
self.positional_args.py_result(),
keyword_code)
code.putln(
"%s = %s; %s" % (
self.result(),
call_code,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
class AsTupleNode(ExprNode):
# Convert argument to tuple. Used for normalising
# the * argument of a function call.
#
# arg ExprNode
subexprs = ['arg']
def calculate_constant_result(self):
self.constant_result = tuple(self.base.constant_result)
def compile_time_value(self, denv):
arg = self.arg.compile_time_value(denv)
try:
return tuple(arg)
except Exception, e:
self.compile_time_value_error(e)
def analyse_types(self, env):
self.arg.analyse_types(env)
self.arg = self.arg.coerce_to_pyobject(env)
self.type = tuple_type
self.is_temp = 1
def may_be_none(self):
return False
nogil_check = Node.gil_error
gil_message = "Constructing Python tuple"
def generate_result_code(self, code):
code.putln(
"%s = PySequence_Tuple(%s); %s" % (
self.result(),
self.arg.py_result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
class AttributeNode(ExprNode):
# obj.attribute
#
# obj ExprNode
# attribute string
# needs_none_check boolean Used if obj is an extension type.
# If set to True, it is known that the type is not None.
#
# Used internally:
#
# is_py_attr boolean Is a Python getattr operation
# member string C name of struct member
# is_called boolean Function call is being done on result
# entry Entry Symbol table entry of attribute
is_attribute = 1
subexprs = ['obj']
type = PyrexTypes.error_type
entry = None
is_called = 0
needs_none_check = True
def as_cython_attribute(self):
if isinstance(self.obj, NameNode) and self.obj.is_cython_module:
return self.attribute
cy = self.obj.as_cython_attribute()
if cy:
return "%s.%s" % (cy, self.attribute)
def coerce_to(self, dst_type, env):
# If coercing to a generic pyobject and this is a cpdef function
# we can create the corresponding attribute
if dst_type is py_object_type:
entry = self.entry
if entry and entry.is_cfunction and entry.as_variable:
# must be a cpdef function
self.is_temp = 1
self.entry = entry.as_variable
self.analyse_as_python_attribute(env)
return self
return ExprNode.coerce_to(self, dst_type, env)
def calculate_constant_result(self):
attr = self.attribute
if attr.startswith("__") and attr.endswith("__"):
return
self.constant_result = getattr(self.obj.constant_result, attr)
def compile_time_value(self, denv):
attr = self.attribute
if attr.startswith("__") and attr.endswith("__"):
error(self.pos,
"Invalid attribute name '%s' in compile-time expression" % attr)
return None
obj = self.obj.compile_time_value(denv)
try:
return getattr(obj, attr)
except Exception, e:
self.compile_time_value_error(e)
def type_dependencies(self, env):
return self.obj.type_dependencies(env)
def infer_type(self, env):
if self.analyse_as_cimported_attribute(env, 0):
return self.entry.type
elif self.analyse_as_unbound_cmethod(env):
return self.entry.type
else:
self.analyse_attribute(env, obj_type = self.obj.infer_type(env))
return self.type
def analyse_target_declaration(self, env):
pass
def analyse_target_types(self, env):
self.analyse_types(env, target = 1)
def analyse_types(self, env, target = 0):
if self.analyse_as_cimported_attribute(env, target):
return
if not target and self.analyse_as_unbound_cmethod(env):
return
self.analyse_as_ordinary_attribute(env, target)
def analyse_as_cimported_attribute(self, env, target):
# Try to interpret this as a reference to an imported
# C const, type, var or function. If successful, mutates
# this node into a NameNode and returns 1, otherwise
# returns 0.
module_scope = self.obj.analyse_as_module(env)
if module_scope:
entry = module_scope.lookup_here(self.attribute)
if entry and (
entry.is_cglobal or entry.is_cfunction
or entry.is_type or entry.is_const):
self.mutate_into_name_node(env, entry, target)
return 1
return 0
def analyse_as_unbound_cmethod(self, env):
# Try to interpret this as a reference to an unbound
# C method of an extension type. If successful, mutates
# this node into a NameNode and returns 1, otherwise
# returns 0.
type = self.obj.analyse_as_extension_type(env)
if type:
entry = type.scope.lookup_here(self.attribute)
if entry and entry.is_cmethod:
# Create a temporary entry describing the C method
# as an ordinary function.
ubcm_entry = Symtab.Entry(entry.name,
"%s->%s" % (type.vtabptr_cname, entry.cname),
entry.type)
ubcm_entry.is_cfunction = 1
ubcm_entry.func_cname = entry.func_cname
ubcm_entry.is_unbound_cmethod = 1
self.mutate_into_name_node(env, ubcm_entry, None)
return 1
return 0
def analyse_as_type(self, env):
module_scope = self.obj.analyse_as_module(env)
if module_scope:
return module_scope.lookup_type(self.attribute)
if not isinstance(self.obj, (UnicodeNode, StringNode, BytesNode)):
base_type = self.obj.analyse_as_type(env)
if base_type and hasattr(base_type, 'scope'):
return base_type.scope.lookup_type(self.attribute)
return None
def analyse_as_extension_type(self, env):
# Try to interpret this as a reference to an extension type
# in a cimported module. Returns the extension type, or None.
module_scope = self.obj.analyse_as_module(env)
if module_scope:
entry = module_scope.lookup_here(self.attribute)
if entry and entry.is_type and entry.type.is_extension_type:
return entry.type
return None
def analyse_as_module(self, env):
# Try to interpret this as a reference to a cimported module
# in another cimported module. Returns the module scope, or None.
module_scope = self.obj.analyse_as_module(env)
if module_scope:
entry = module_scope.lookup_here(self.attribute)
if entry and entry.as_module:
return entry.as_module
return None
def mutate_into_name_node(self, env, entry, target):
# Mutate this node into a NameNode and complete the
# analyse_types phase.
self.__class__ = NameNode
self.name = self.attribute
self.entry = entry
del self.obj
del self.attribute
if target:
NameNode.analyse_target_types(self, env)
else:
NameNode.analyse_rvalue_entry(self, env)
def analyse_as_ordinary_attribute(self, env, target):
self.obj.analyse_types(env)
self.analyse_attribute(env)
if self.entry and self.entry.is_cmethod and not self.is_called:
# error(self.pos, "C method can only be called")
pass
## Reference to C array turns into pointer to first element.
#while self.type.is_array:
# self.type = self.type.element_ptr_type()
if self.is_py_attr:
if not target:
self.is_temp = 1
self.result_ctype = py_object_type
def analyse_attribute(self, env, obj_type = None):
# Look up attribute and set self.type and self.member.
self.is_py_attr = 0
self.member = self.attribute
if obj_type is None:
if self.obj.type.is_string:
self.obj = self.obj.coerce_to_pyobject(env)
obj_type = self.obj.type
else:
if obj_type.is_string:
obj_type = py_object_type
if obj_type.is_ptr or obj_type.is_array:
obj_type = obj_type.base_type
self.op = "->"
elif obj_type.is_extension_type:
self.op = "->"
else:
self.op = "."
if obj_type.has_attributes:
entry = None
if obj_type.attributes_known():
entry = obj_type.scope.lookup_here(self.attribute)
if entry and entry.is_member:
entry = None
else:
error(self.pos,
"Cannot select attribute of incomplete type '%s'"
% obj_type)
self.type = PyrexTypes.error_type
return
self.entry = entry
if entry:
if obj_type.is_extension_type and entry.name == "__weakref__":
error(self.pos, "Illegal use of special attribute __weakref__")
# methods need the normal attribute lookup
# because they do not have struct entries
if entry.is_variable or entry.is_cmethod:
self.type = entry.type
self.member = entry.cname
return
else:
# If it's not a variable or C method, it must be a Python
# method of an extension type, so we treat it like a Python
# attribute.
pass
# If we get here, the base object is not a struct/union/extension
# type, or it is an extension type and the attribute is either not
# declared or is declared as a Python method. Treat it as a Python
# attribute reference.
self.analyse_as_python_attribute(env, obj_type)
def analyse_as_python_attribute(self, env, obj_type = None):
if obj_type is None:
obj_type = self.obj.type
self.member = self.attribute
self.type = py_object_type
self.is_py_attr = 1
if not obj_type.is_pyobject and not obj_type.is_error:
if obj_type.can_coerce_to_pyobject(env):
self.obj = self.obj.coerce_to_pyobject(env)
else:
error(self.pos,
"Object of type '%s' has no attribute '%s'" %
(obj_type, self.attribute))
def nogil_check(self, env):
if self.is_py_attr:
self.gil_error()
gil_message = "Accessing Python attribute"
def is_simple(self):
if self.obj:
return self.result_in_temp() or self.obj.is_simple()
else:
return NameNode.is_simple(self)
def is_lvalue(self):
if self.obj:
return 1
else:
return NameNode.is_lvalue(self)
def is_ephemeral(self):
if self.obj:
return self.obj.is_ephemeral()
else:
return NameNode.is_ephemeral(self)
def calculate_result_code(self):
#print "AttributeNode.calculate_result_code:", self.member ###
#print "...obj node =", self.obj, "code", self.obj.result() ###
#print "...obj type", self.obj.type, "ctype", self.obj.ctype() ###
obj = self.obj
obj_code = obj.result_as(obj.type)
#print "...obj_code =", obj_code ###
if self.entry and self.entry.is_cmethod:
if obj.type.is_extension_type:
return "((struct %s *)%s%s%s)->%s" % (
obj.type.vtabstruct_cname, obj_code, self.op,
obj.type.vtabslot_cname, self.member)
else:
return self.member
elif obj.type.is_complex:
return "__Pyx_C%s(%s)" % (self.member.upper(), obj_code)
else:
return "%s%s%s" % (obj_code, self.op, self.member)
def generate_result_code(self, code):
interned_attr_cname = code.intern_identifier(self.attribute)
if self.is_py_attr:
code.putln(
'%s = PyObject_GetAttr(%s, %s); %s' % (
self.result(),
self.obj.py_result(),
interned_attr_cname,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
else:
# result_code contains what is needed, but we may need to insert
# a check and raise an exception
if (self.obj.type.is_extension_type
and self.needs_none_check
and code.globalstate.directives['nonecheck']):
self.put_nonecheck(code)
def generate_assignment_code(self, rhs, code):
interned_attr_cname = code.intern_identifier(self.attribute)
self.obj.generate_evaluation_code(code)
if self.is_py_attr:
code.put_error_if_neg(self.pos,
'PyObject_SetAttr(%s, %s, %s)' % (
self.obj.py_result(),
interned_attr_cname,
rhs.py_result()))
rhs.generate_disposal_code(code)
rhs.free_temps(code)
elif self.obj.type.is_complex:
code.putln("__Pyx_SET_C%s(%s, %s);" % (
self.member.upper(),
self.obj.result_as(self.obj.type),
rhs.result_as(self.ctype())))
else:
if (self.obj.type.is_extension_type
and self.needs_none_check
and code.globalstate.directives['nonecheck']):
self.put_nonecheck(code)
select_code = self.result()
if self.type.is_pyobject and self.use_managed_ref:
rhs.make_owned_reference(code)
code.put_giveref(rhs.py_result())
code.put_gotref(select_code)
code.put_decref(select_code, self.ctype())
code.putln(
"%s = %s;" % (
select_code,
rhs.result_as(self.ctype())))
#rhs.result()))
rhs.generate_post_assignment_code(code)
rhs.free_temps(code)
self.obj.generate_disposal_code(code)
self.obj.free_temps(code)
def generate_deletion_code(self, code):
interned_attr_cname = code.intern_identifier(self.attribute)
self.obj.generate_evaluation_code(code)
if self.is_py_attr or (isinstance(self.entry.scope, Symtab.PropertyScope)
and self.entry.scope.entries.has_key(u'__del__')):
code.put_error_if_neg(self.pos,
'PyObject_DelAttr(%s, %s)' % (
self.obj.py_result(),
interned_attr_cname))
else:
error(self.pos, "Cannot delete C attribute of extension type")
self.obj.generate_disposal_code(code)
self.obj.free_temps(code)
def annotate(self, code):
if self.is_py_attr:
code.annotate(self.pos, AnnotationItem('py_attr', 'python attribute', size=len(self.attribute)))
else:
code.annotate(self.pos, AnnotationItem('c_attr', 'c attribute', size=len(self.attribute)))
def put_nonecheck(self, code):
code.globalstate.use_utility_code(raise_noneattr_error_utility_code)
code.putln("if (%s) {" % code.unlikely("%s == Py_None") % self.obj.result_as(PyrexTypes.py_object_type))
code.putln("__Pyx_RaiseNoneAttributeError(\"%s\");" % self.attribute)
code.putln(code.error_goto(self.pos))
code.putln("}")
#-------------------------------------------------------------------
#
# Constructor nodes
#
#-------------------------------------------------------------------
class StarredTargetNode(ExprNode):
# A starred expression like "*a"
#
# This is only allowed in sequence assignment targets such as
#
# a, *b = (1,2,3,4) => a = 1 ; b = [2,3,4]
#
# and will be removed during type analysis (or generate an error
# if it's found at unexpected places).
#
# target ExprNode
subexprs = ['target']
is_starred = 1
type = py_object_type
is_temp = 1
def __init__(self, pos, target):
self.pos = pos
self.target = target
def analyse_declarations(self, env):
error(self.pos, "can use starred expression only as assignment target")
self.target.analyse_declarations(env)
def analyse_types(self, env):
error(self.pos, "can use starred expression only as assignment target")
self.target.analyse_types(env)
self.type = self.target.type
def analyse_target_declaration(self, env):
self.target.analyse_target_declaration(env)
def analyse_target_types(self, env):
self.target.analyse_target_types(env)
self.type = self.target.type
def calculate_result_code(self):
return ""
def generate_result_code(self, code):
pass
class SequenceNode(ExprNode):
# Base class for list and tuple constructor nodes.
# Contains common code for performing sequence unpacking.
#
# args [ExprNode]
# iterator ExprNode
# unpacked_items [ExprNode] or None
# coerced_unpacked_items [ExprNode] or None
subexprs = ['args']
is_sequence_constructor = 1
unpacked_items = None
def compile_time_value_list(self, denv):
return [arg.compile_time_value(denv) for arg in self.args]
def replace_starred_target_node(self):
# replace a starred node in the targets by the contained expression
self.starred_assignment = False
args = []
for arg in self.args:
if arg.is_starred:
if self.starred_assignment:
error(arg.pos, "more than 1 starred expression in assignment")
self.starred_assignment = True
arg = arg.target
arg.is_starred = True
args.append(arg)
self.args = args
def analyse_target_declaration(self, env):
self.replace_starred_target_node()
for arg in self.args:
arg.analyse_target_declaration(env)
def analyse_types(self, env, skip_children=False):
for i in range(len(self.args)):
arg = self.args[i]
if not skip_children: arg.analyse_types(env)
self.args[i] = arg.coerce_to_pyobject(env)
self.type = py_object_type
self.is_temp = 1
def may_be_none(self):
return False
def analyse_target_types(self, env):
self.iterator = PyTempNode(self.pos, env)
self.unpacked_items = []
self.coerced_unpacked_items = []
for arg in self.args:
arg.analyse_target_types(env)
if arg.is_starred:
if not arg.type.assignable_from(Builtin.list_type):
error(arg.pos,
"starred target must have Python object (list) type")
if arg.type is py_object_type:
arg.type = Builtin.list_type
unpacked_item = PyTempNode(self.pos, env)
coerced_unpacked_item = unpacked_item.coerce_to(arg.type, env)
self.unpacked_items.append(unpacked_item)
self.coerced_unpacked_items.append(coerced_unpacked_item)
self.type = py_object_type
def generate_result_code(self, code):
self.generate_operation_code(code)
def generate_assignment_code(self, rhs, code):
if self.starred_assignment:
self.generate_starred_assignment_code(rhs, code)
else:
self.generate_parallel_assignment_code(rhs, code)
for item in self.unpacked_items:
item.release(code)
rhs.free_temps(code)
def generate_parallel_assignment_code(self, rhs, code):
# Need to work around the fact that generate_evaluation_code
# allocates the temps in a rather hacky way -- the assignment
# is evaluated twice, within each if-block.
if rhs.type is tuple_type:
tuple_check = "likely(%s != Py_None)"
else:
tuple_check = "PyTuple_CheckExact(%s)"
code.putln(
"if (%s && likely(PyTuple_GET_SIZE(%s) == %s)) {" % (
tuple_check % rhs.py_result(),
rhs.py_result(),
len(self.args)))
code.putln("PyObject* tuple = %s;" % rhs.py_result())
for item in self.unpacked_items:
item.allocate(code)
for i in range(len(self.args)):
item = self.unpacked_items[i]
code.put(
"%s = PyTuple_GET_ITEM(tuple, %s); " % (
item.result(),
i))
code.put_incref(item.result(), item.ctype())
value_node = self.coerced_unpacked_items[i]
value_node.generate_evaluation_code(code)
rhs.generate_disposal_code(code)
for i in range(len(self.args)):
self.args[i].generate_assignment_code(
self.coerced_unpacked_items[i], code)
code.putln("} else {")
if rhs.type is tuple_type:
code.globalstate.use_utility_code(tuple_unpacking_error_code)
code.putln("__Pyx_UnpackTupleError(%s, %s);" % (
rhs.py_result(), len(self.args)))
code.putln(code.error_goto(self.pos))
else:
code.globalstate.use_utility_code(unpacking_utility_code)
self.iterator.allocate(code)
code.putln(
"%s = PyObject_GetIter(%s); %s" % (
self.iterator.result(),
rhs.py_result(),
code.error_goto_if_null(self.iterator.result(), self.pos)))
code.put_gotref(self.iterator.py_result())
rhs.generate_disposal_code(code)
for i in range(len(self.args)):
item = self.unpacked_items[i]
unpack_code = "__Pyx_UnpackItem(%s, %d)" % (
self.iterator.py_result(), i)
code.putln(
"%s = %s; %s" % (
item.result(),
typecast(item.ctype(), py_object_type, unpack_code),
code.error_goto_if_null(item.result(), self.pos)))
code.put_gotref(item.py_result())
value_node = self.coerced_unpacked_items[i]
value_node.generate_evaluation_code(code)
code.put_error_if_neg(self.pos, "__Pyx_EndUnpack(%s, %d)" % (
self.iterator.py_result(),
len(self.args)))
if debug_disposal_code:
print("UnpackNode.generate_assignment_code:")
print("...generating disposal code for %s" % self.iterator)
self.iterator.generate_disposal_code(code)
self.iterator.free_temps(code)
self.iterator.release(code)
for i in range(len(self.args)):
self.args[i].generate_assignment_code(
self.coerced_unpacked_items[i], code)
code.putln("}")
def generate_starred_assignment_code(self, rhs, code):
code.globalstate.use_utility_code(unpacking_utility_code)
for i, arg in enumerate(self.args):
if arg.is_starred:
starred_target = self.unpacked_items[i]
fixed_args_left = self.args[:i]
fixed_args_right = self.args[i+1:]
break
self.iterator.allocate(code)
code.putln(
"%s = PyObject_GetIter(%s); %s" % (
self.iterator.result(),
rhs.py_result(),
code.error_goto_if_null(self.iterator.result(), self.pos)))
code.put_gotref(self.iterator.py_result())
rhs.generate_disposal_code(code)
for item in self.unpacked_items:
item.allocate(code)
for i in range(len(fixed_args_left)):
item = self.unpacked_items[i]
unpack_code = "__Pyx_UnpackItem(%s, %d)" % (
self.iterator.py_result(), i)
code.putln(
"%s = %s; %s" % (
item.result(),
typecast(item.ctype(), py_object_type, unpack_code),
code.error_goto_if_null(item.result(), self.pos)))
code.put_gotref(item.py_result())
value_node = self.coerced_unpacked_items[i]
value_node.generate_evaluation_code(code)
target_list = starred_target.result()
code.putln("%s = PySequence_List(%s); %s" % (
target_list, self.iterator.py_result(),
code.error_goto_if_null(target_list, self.pos)))
code.put_gotref(target_list)
if fixed_args_right:
code.globalstate.use_utility_code(raise_need_more_values_to_unpack)
unpacked_right_args = self.unpacked_items[-len(fixed_args_right):]
code.putln("if (unlikely(PyList_GET_SIZE(%s) < %d)) {" % (
(target_list, len(unpacked_right_args))))
code.put("__Pyx_RaiseNeedMoreValuesError(%d+PyList_GET_SIZE(%s)); %s" % (
len(fixed_args_left), target_list,
code.error_goto(self.pos)))
code.putln('}')
for i, (arg, coerced_arg) in enumerate(zip(unpacked_right_args[::-1],
self.coerced_unpacked_items[::-1])):
code.putln(
"%s = PyList_GET_ITEM(%s, PyList_GET_SIZE(%s)-1); " % (
arg.py_result(),
target_list, target_list))
# resize the list the hard way
code.putln("((PyVarObject*)%s)->ob_size--;" % target_list)
code.put_gotref(arg.py_result())
coerced_arg.generate_evaluation_code(code)
self.iterator.generate_disposal_code(code)
self.iterator.free_temps(code)
self.iterator.release(code)
for i in range(len(self.args)):
self.args[i].generate_assignment_code(
self.coerced_unpacked_items[i], code)
def annotate(self, code):
for arg in self.args:
arg.annotate(code)
if self.unpacked_items:
for arg in self.unpacked_items:
arg.annotate(code)
for arg in self.coerced_unpacked_items:
arg.annotate(code)
class TupleNode(SequenceNode):
# Tuple constructor.
type = tuple_type
gil_message = "Constructing Python tuple"
def analyse_types(self, env, skip_children=False):
if len(self.args) == 0:
self.is_temp = 0
self.is_literal = 1
else:
SequenceNode.analyse_types(self, env, skip_children)
def calculate_result_code(self):
if len(self.args) > 0:
error(self.pos, "Positive length tuples must be constructed.")
else:
return Naming.empty_tuple
def calculate_constant_result(self):
self.constant_result = tuple([
arg.constant_result for arg in self.args])
def compile_time_value(self, denv):
values = self.compile_time_value_list(denv)
try:
return tuple(values)
except Exception, e:
self.compile_time_value_error(e)
def generate_operation_code(self, code):
if len(self.args) == 0:
# result_code is Naming.empty_tuple
return
code.putln(
"%s = PyTuple_New(%s); %s" % (
self.result(),
len(self.args),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
for i in range(len(self.args)):
arg = self.args[i]
if not arg.result_in_temp():
code.put_incref(arg.result(), arg.ctype())
code.putln(
"PyTuple_SET_ITEM(%s, %s, %s);" % (
self.result(),
i,
arg.py_result()))
code.put_giveref(arg.py_result())
def generate_subexpr_disposal_code(self, code):
# We call generate_post_assignment_code here instead
# of generate_disposal_code, because values were stored
# in the tuple using a reference-stealing operation.
for arg in self.args:
arg.generate_post_assignment_code(code)
# Should NOT call free_temps -- this is invoked by the default
# generate_evaluation_code which will do that.
class ListNode(SequenceNode):
# List constructor.
# obj_conversion_errors [PyrexError] used internally
# orignial_args [ExprNode] used internally
obj_conversion_errors = []
gil_message = "Constructing Python list"
def type_dependencies(self, env):
return ()
def infer_type(self, env):
# TOOD: Infer non-object list arrays.
return list_type
def analyse_expressions(self, env):
SequenceNode.analyse_expressions(self, env)
self.coerce_to_pyobject(env)
def analyse_types(self, env):
hold_errors()
self.original_args = list(self.args)
SequenceNode.analyse_types(self, env)
self.type = list_type
self.obj_conversion_errors = held_errors()
release_errors(ignore=True)
def coerce_to(self, dst_type, env):
if dst_type.is_pyobject:
for err in self.obj_conversion_errors:
report_error(err)
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_ptr:
base_type = dst_type.base_type
self.type = PyrexTypes.CArrayType(base_type, len(self.args))
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_struct:
if len(self.args) > len(dst_type.scope.var_entries):
error(self.pos, "Too may 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)
for i, (arg, member) in enumerate(zip(self.original_args, dst_type.scope.var_entries)):
if isinstance(arg, CoerceToPyTypeNode):
arg = arg.arg
self.args[i] = arg.coerce_to(member.type, env)
self.type = dst_type
else:
self.type = error_type
error(self.pos, "Cannot coerce list to type '%s'" % dst_type)
return self
def release_temp(self, env):
if self.type.is_array:
# To be valid C++, we must allocate the memory on the stack
# manually and be sure not to reuse it for something else.
pass
else:
SequenceNode.release_temp(self, env)
def calculate_constant_result(self):
self.constant_result = [
arg.constant_result for arg in self.args]
def compile_time_value(self, denv):
return self.compile_time_value_list(denv)
def generate_operation_code(self, code):
if self.type.is_pyobject:
for err in self.obj_conversion_errors:
report_error(err)
code.putln("%s = PyList_New(%s); %s" %
(self.result(),
len(self.args),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
for i in range(len(self.args)):
arg = self.args[i]
#if not arg.is_temp:
if not arg.result_in_temp():
code.put_incref(arg.result(), arg.ctype())
code.putln("PyList_SET_ITEM(%s, %s, %s);" %
(self.result(),
i,
arg.py_result()))
code.put_giveref(arg.py_result())
elif self.type.is_array:
for i, arg in enumerate(self.args):
code.putln("%s[%s] = %s;" % (
self.result(),
i,
arg.result()))
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()))
else:
raise InternalError("List type never specified")
def generate_subexpr_disposal_code(self, code):
# We call generate_post_assignment_code here instead
# of generate_disposal_code, because values were stored
# in the list using a reference-stealing operation.
for arg in self.args:
arg.generate_post_assignment_code(code)
# Should NOT call free_temps -- this is invoked by the default
# generate_evaluation_code which will do that.
class ScopedExprNode(ExprNode):
# Abstract base class for ExprNodes that have their own local
# scope, such as generator expressions.
#
# expr_scope Scope the inner scope of the expression
subexprs = []
expr_scope = None
def analyse_types(self, env):
# nothing to do here, the children will be analysed separately
pass
def analyse_expressions(self, env):
# nothing to do here, the children will be analysed separately
pass
def analyse_scoped_expressions(self, env):
# this is called with the expr_scope as env
pass
def init_scope(self, outer_scope, expr_scope=None):
self.expr_scope = expr_scope
class ComprehensionNode(ScopedExprNode):
subexprs = ["target"]
child_attrs = ["loop", "append"]
# leak loop variables or not? non-leaking Py3 behaviour is
# default, except for list comprehensions where the behaviour
# differs in Py2 and Py3 (see Parsing.py)
has_local_scope = True
def infer_type(self, env):
return self.target.infer_type(env)
def analyse_declarations(self, env):
self.append.target = self # this is used in the PyList_Append of the inner loop
self.init_scope(env)
if self.expr_scope is not None:
self.loop.analyse_declarations(self.expr_scope)
else:
self.loop.analyse_declarations(env)
def init_scope(self, outer_scope, expr_scope=None):
if expr_scope is not None:
self.expr_scope = expr_scope
elif self.has_local_scope:
self.expr_scope = Symtab.GeneratorExpressionScope(outer_scope)
else:
self.expr_scope = None
def analyse_types(self, env):
self.target.analyse_expressions(env)
self.type = self.target.type
if not self.has_local_scope:
self.loop.analyse_expressions(env)
def analyse_expressions(self, env):
self.analyse_types(env)
def analyse_scoped_expressions(self, env):
if self.has_local_scope:
self.loop.analyse_expressions(env)
def may_be_none(self):
return False
def calculate_result_code(self):
return self.target.result()
def generate_result_code(self, code):
self.generate_operation_code(code)
def generate_operation_code(self, code):
self.loop.generate_execution_code(code)
def annotate(self, code):
self.loop.annotate(code)
class ComprehensionAppendNode(Node):
# Need to be careful to avoid infinite recursion:
# target must not be in child_attrs/subexprs
child_attrs = ['expr']
type = PyrexTypes.c_int_type
def analyse_expressions(self, env):
self.expr.analyse_expressions(env)
if not self.expr.type.is_pyobject:
self.expr = self.expr.coerce_to_pyobject(env)
def generate_execution_code(self, code):
if self.target.type is list_type:
function = "PyList_Append"
elif self.target.type is set_type:
function = "PySet_Add"
else:
raise InternalError(
"Invalid type for comprehension node: %s" % self.target.type)
self.expr.generate_evaluation_code(code)
code.putln(code.error_goto_if("%s(%s, (PyObject*)%s)" % (
function,
self.target.result(),
self.expr.result()
), self.pos))
self.expr.generate_disposal_code(code)
self.expr.free_temps(code)
def generate_function_definitions(self, env, code):
self.expr.generate_function_definitions(env, code)
def annotate(self, code):
self.expr.annotate(code)
class DictComprehensionAppendNode(ComprehensionAppendNode):
child_attrs = ['key_expr', 'value_expr']
def analyse_expressions(self, env):
self.key_expr.analyse_expressions(env)
if not self.key_expr.type.is_pyobject:
self.key_expr = self.key_expr.coerce_to_pyobject(env)
self.value_expr.analyse_expressions(env)
if not self.value_expr.type.is_pyobject:
self.value_expr = self.value_expr.coerce_to_pyobject(env)
def generate_execution_code(self, code):
self.key_expr.generate_evaluation_code(code)
self.value_expr.generate_evaluation_code(code)
code.putln(code.error_goto_if("PyDict_SetItem(%s, (PyObject*)%s, (PyObject*)%s)" % (
self.target.result(),
self.key_expr.result(),
self.value_expr.result()
), self.pos))
self.key_expr.generate_disposal_code(code)
self.key_expr.free_temps(code)
self.value_expr.generate_disposal_code(code)
self.value_expr.free_temps(code)
def generate_function_definitions(self, env, code):
self.key_expr.generate_function_definitions(env, code)
self.value_expr.generate_function_definitions(env, code)
def annotate(self, code):
self.key_expr.annotate(code)
self.value_expr.annotate(code)
class GeneratorExpressionNode(ScopedExprNode):
# A generator expression, e.g. (i for i in range(10))
#
# Result is a generator.
#
# loop ForStatNode the for-loop, containing a YieldExprNode
child_attrs = ["loop"]
type = py_object_type
def analyse_declarations(self, env):
self.init_scope(env)
self.loop.analyse_declarations(self.expr_scope)
def init_scope(self, outer_scope, expr_scope=None):
if expr_scope is not None:
self.expr_scope = expr_scope
else:
self.expr_scope = Symtab.GeneratorExpressionScope(outer_scope)
def analyse_types(self, env):
self.is_temp = True
def analyse_scoped_expressions(self, env):
self.loop.analyse_expressions(env)
def may_be_none(self):
return False
def annotate(self, code):
self.loop.annotate(code)
class InlinedGeneratorExpressionNode(GeneratorExpressionNode):
# An inlined generator expression for which the result is
# calculated inside of the loop. This will only be created by
# transforms when replacing builtin calls on generator
# expressions.
#
# loop ForStatNode the for-loop, not containing any YieldExprNodes
# result_node ResultRefNode the reference to the result value temp
# orig_func String the name of the builtin function this node replaces
child_attrs = ["loop"]
def analyse_types(self, env):
self.type = self.result_node.type
self.is_temp = True
def coerce_to(self, dst_type, env):
if self.orig_func == 'sum' and dst_type.is_numeric:
# we can optimise by dropping the aggregation variable into C
self.result_node.type = self.type = dst_type
return self
return GeneratorExpressionNode.coerce_to(self, dst_type, env)
def generate_result_code(self, code):
self.result_node.result_code = self.result()
self.loop.generate_execution_code(code)
class SetNode(ExprNode):
# Set constructor.
type = set_type
subexprs = ['args']
gil_message = "Constructing Python set"
def analyse_types(self, env):
for i in range(len(self.args)):
arg = self.args[i]
arg.analyse_types(env)
self.args[i] = arg.coerce_to_pyobject(env)
self.type = set_type
self.is_temp = 1
def may_be_none(self):
return False
def calculate_constant_result(self):
self.constant_result = set([
arg.constant_result for arg in self.args])
def compile_time_value(self, denv):
values = [arg.compile_time_value(denv) for arg in self.args]
try:
return set(values)
except Exception, e:
self.compile_time_value_error(e)
def generate_evaluation_code(self, code):
code.globalstate.use_utility_code(Builtin.py23_set_utility_code)
self.allocate_temp_result(code)
code.putln(
"%s = PySet_New(0); %s" % (
self.result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
for arg in self.args:
arg.generate_evaluation_code(code)
code.putln(
code.error_goto_if_neg(
"PySet_Add(%s, %s)" % (self.result(), arg.py_result()),
self.pos))
arg.generate_disposal_code(code)
arg.free_temps(code)
class DictNode(ExprNode):
# Dictionary constructor.
#
# key_value_pairs [DictItemNode]
#
# obj_conversion_errors [PyrexError] used internally
subexprs = ['key_value_pairs']
is_temp = 1
type = dict_type
obj_conversion_errors = []
def calculate_constant_result(self):
self.constant_result = dict([
item.constant_result for item in self.key_value_pairs])
def compile_time_value(self, denv):
pairs = [(item.key.compile_time_value(denv), item.value.compile_time_value(denv))
for item in self.key_value_pairs]
try:
return dict(pairs)
except Exception, e:
self.compile_time_value_error(e)
def type_dependencies(self, env):
return ()
def infer_type(self, env):
# TOOD: Infer struct constructors.
return dict_type
def analyse_types(self, env):
hold_errors()
for item in self.key_value_pairs:
item.analyse_types(env)
self.obj_conversion_errors = held_errors()
release_errors(ignore=True)
def may_be_none(self):
return False
def coerce_to(self, dst_type, env):
if dst_type.is_pyobject:
self.release_errors()
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:
self.type = dst_type
if not dst_type.is_struct and len(self.key_value_pairs) != 1:
error(self.pos, "Exactly one field must be specified to convert to union '%s'" % dst_type)
elif dst_type.is_struct and len(self.key_value_pairs) < len(dst_type.scope.var_entries):
warning(self.pos, "Not all members given for struct '%s'" % dst_type, 1)
for item in self.key_value_pairs:
if isinstance(item.key, CoerceToPyTypeNode):
item.key = item.key.arg
if not isinstance(item.key, (UnicodeNode, StringNode, BytesNode)):
error(item.key.pos, "Invalid struct field identifier")
item.key = StringNode(item.key.pos, value="")
else:
key = str(item.key.value) # converts string literals to unicode in Py3
member = dst_type.scope.lookup_here(key)
if not member:
error(item.key.pos, "struct '%s' has no field '%s'" % (dst_type, key))
else:
value = item.value
if isinstance(value, CoerceToPyTypeNode):
value = value.arg
item.value = value.coerce_to(member.type, env)
else:
self.type = error_type
error(self.pos, "Cannot interpret dict as type '%s'" % dst_type)
return self
def release_errors(self):
for err in self.obj_conversion_errors:
report_error(err)
self.obj_conversion_errors = []
gil_message = "Constructing Python dict"
def generate_evaluation_code(self, code):
# Custom method used here because key-value
# pairs are evaluated and used one at a time.
code.mark_pos(self.pos)
self.allocate_temp_result(code)
if self.type.is_pyobject:
self.release_errors()
code.putln(
"%s = PyDict_New(); %s" % (
self.result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
for item in self.key_value_pairs:
item.generate_evaluation_code(code)
if self.type.is_pyobject:
code.put_error_if_neg(self.pos,
"PyDict_SetItem(%s, %s, %s)" % (
self.result(),
item.key.py_result(),
item.value.py_result()))
else:
code.putln("%s.%s = %s;" % (
self.result(),
item.key.value,
item.value.result()))
item.generate_disposal_code(code)
item.free_temps(code)
def annotate(self, code):
for item in self.key_value_pairs:
item.annotate(code)
class DictItemNode(ExprNode):
# Represents a single item in a DictNode
#
# key ExprNode
# value ExprNode
subexprs = ['key', 'value']
nogil_check = None # Parent DictNode takes care of it
def calculate_constant_result(self):
self.constant_result = (
self.key.constant_result, self.value.constant_result)
def analyse_types(self, env):
self.key.analyse_types(env)
self.value.analyse_types(env)
self.key = self.key.coerce_to_pyobject(env)
self.value = self.value.coerce_to_pyobject(env)
def generate_evaluation_code(self, code):
self.key.generate_evaluation_code(code)
self.value.generate_evaluation_code(code)
def generate_disposal_code(self, code):
self.key.generate_disposal_code(code)
self.value.generate_disposal_code(code)
def free_temps(self, code):
self.key.free_temps(code)
self.value.free_temps(code)
def __iter__(self):
return iter([self.key, self.value])
class ClassNode(ExprNode):
# Helper class used in the implementation of Python
# class definitions. Constructs a class object given
# a name, tuple of bases and class dictionary.
#
# name EncodedString Name of the class
# bases ExprNode Base class tuple
# dict ExprNode Class dict (not owned by this node)
# doc ExprNode or None Doc string
# module_name string Name of defining module
subexprs = ['bases', 'doc']
def analyse_types(self, env):
self.bases.analyse_types(env)
if self.doc:
self.doc.analyse_types(env)
self.doc = self.doc.coerce_to_pyobject(env)
self.module_name = env.global_scope().qualified_name
self.type = py_object_type
self.is_temp = 1
env.use_utility_code(create_class_utility_code);
def may_be_none(self):
return False
gil_message = "Constructing Python class"
def generate_result_code(self, code):
cname = code.intern_identifier(self.name)
if self.doc:
code.put_error_if_neg(self.pos,
'PyDict_SetItemString(%s, "__doc__", %s)' % (
self.dict.py_result(),
self.doc.py_result()))
code.putln(
'%s = __Pyx_CreateClass(%s, %s, %s, "%s"); %s' % (
self.result(),
self.bases.py_result(),
self.dict.py_result(),
cname,
self.module_name,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
class BoundMethodNode(ExprNode):
# Helper class used in the implementation of Python
# class definitions. Constructs an bound method
# object from a class and a function.
#
# function ExprNode Function object
# self_object ExprNode self object
subexprs = ['function']
def analyse_types(self, env):
self.function.analyse_types(env)
self.type = py_object_type
self.is_temp = 1
gil_message = "Constructing an bound method"
def generate_result_code(self, code):
code.putln(
"%s = PyMethod_New(%s, %s, (PyObject*)%s->ob_type); %s" % (
self.result(),
self.function.py_result(),
self.self_object.py_result(),
self.self_object.py_result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
class UnboundMethodNode(ExprNode):
# Helper class used in the implementation of Python
# class definitions. Constructs an unbound method
# object from a class and a function.
#
# function ExprNode Function object
type = py_object_type
is_temp = 1
subexprs = ['function']
def analyse_types(self, env):
self.function.analyse_types(env)
def may_be_none(self):
return False
gil_message = "Constructing an unbound method"
def generate_result_code(self, code):
class_cname = code.pyclass_stack[-1].classobj.result()
code.putln(
"%s = PyMethod_New(%s, 0, %s); %s" % (
self.result(),
self.function.py_result(),
class_cname,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
class PyCFunctionNode(ExprNode):
# Helper class used in the implementation of Python
# class definitions. Constructs a PyCFunction object
# from a PyMethodDef struct.
#
# pymethdef_cname string PyMethodDef structure
# self_object ExprNode or None
# binding bool
subexprs = []
self_object = None
binding = False
type = py_object_type
is_temp = 1
def analyse_types(self, env):
if self.binding:
env.use_utility_code(binding_cfunc_utility_code)
def may_be_none(self):
return False
gil_message = "Constructing Python function"
def self_result_code(self):
if self.self_object is None:
self_result = "NULL"
else:
self_result = self.self_object.py_result()
return self_result
def generate_result_code(self, code):
if self.binding:
constructor = "%s_New" % Naming.binding_cfunc
else:
constructor = "PyCFunction_New"
code.putln(
"%s = %s(&%s, %s); %s" % (
self.result(),
constructor,
self.pymethdef_cname,
self.self_result_code(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
class InnerFunctionNode(PyCFunctionNode):
# Special PyCFunctionNode that depends on a closure class
#
binding = True
def self_result_code(self):
return "((PyObject*)%s)" % Naming.cur_scope_cname
class LambdaNode(InnerFunctionNode):
# Lambda expression node (only used as a function reference)
#
# args [CArgDeclNode] formal arguments
# star_arg PyArgDeclNode or None * argument
# starstar_arg PyArgDeclNode or None ** argument
# lambda_name string a module-globally unique lambda name
# result_expr ExprNode
# def_node DefNode the underlying function 'def' node
child_attrs = ['def_node']
def_node = None
name = StringEncoding.EncodedString('')
def analyse_declarations(self, env):
#self.def_node.needs_closure = self.needs_closure
self.def_node.analyse_declarations(env)
self.pymethdef_cname = self.def_node.entry.pymethdef_cname
env.add_lambda_def(self.def_node)
class YieldExprNode(ExprNode):
# Yield expression node
#
# arg ExprNode the value to return from the generator
# label_name string name of the C label used for this yield
subexprs = ['arg']
type = py_object_type
def analyse_types(self, env):
self.is_temp = 1
if self.arg is not None:
self.arg.analyse_types(env)
if not self.arg.type.is_pyobject:
self.arg = self.arg.coerce_to_pyobject(env)
error(self.pos, "Generators are not supported")
def generate_result_code(self, code):
self.label_name = code.new_label('resume_from_yield')
code.use_label(self.label_name)
code.putln("/* FIXME: save temporary variables */")
code.putln("/* FIXME: return from function, yielding value */")
code.put_label(self.label_name)
code.putln("/* FIXME: restore temporary variables and */")
code.putln("/* FIXME: extract sent value from closure */")
#-------------------------------------------------------------------
#
# Unary operator nodes
#
#-------------------------------------------------------------------
compile_time_unary_operators = {
'not': operator.not_,
'~': operator.inv,
'-': operator.neg,
'+': operator.pos,
}
class UnopNode(ExprNode):
# operator string
# operand ExprNode
#
# Processing during analyse_expressions phase:
#
# analyse_c_operation
# Called when the operand is not a pyobject.
# - Check operand type and coerce if needed.
# - Determine result type and result code fragment.
# - Allocate temporary for result if needed.
subexprs = ['operand']
infix = True
def calculate_constant_result(self):
func = compile_time_unary_operators[self.operator]
self.constant_result = func(self.operand.constant_result)
def compile_time_value(self, denv):
func = compile_time_unary_operators.get(self.operator)
if not func:
error(self.pos,
"Unary '%s' not supported in compile-time expression"
% self.operator)
operand = self.operand.compile_time_value(denv)
try:
return func(operand)
except Exception, e:
self.compile_time_value_error(e)
def infer_type(self, env):
operand_type = self.operand.infer_type(env)
if operand_type.is_pyobject:
return py_object_type
else:
return operand_type
def analyse_types(self, env):
self.operand.analyse_types(env)
if self.is_py_operation():
self.coerce_operand_to_pyobject(env)
self.type = py_object_type
self.is_temp = 1
elif self.is_cpp_operation():
self.analyse_cpp_operation(env)
else:
self.analyse_c_operation(env)
def check_const(self):
return self.operand.check_const()
def is_py_operation(self):
return self.operand.type.is_pyobject
def nogil_check(self, env):
if self.is_py_operation():
self.gil_error()
def is_cpp_operation(self):
type = self.operand.type
return type.is_cpp_class
def coerce_operand_to_pyobject(self, env):
self.operand = self.operand.coerce_to_pyobject(env)
def generate_result_code(self, code):
if self.operand.type.is_pyobject:
self.generate_py_operation_code(code)
def generate_py_operation_code(self, code):
function = self.py_operation_function()
code.putln(
"%s = %s(%s); %s" % (
self.result(),
function,
self.operand.py_result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
def type_error(self):
if not self.operand.type.is_error:
error(self.pos, "Invalid operand type for '%s' (%s)" %
(self.operator, self.operand.type))
self.type = PyrexTypes.error_type
def analyse_cpp_operation(self, env):
type = self.operand.type
if type.is_ptr:
type = type.base_type
function = type.scope.lookup("operator%s" % self.operator)
if not function:
error(self.pos, "'%s' operator not defined for %s"
% (self.operator, type))
self.type_error()
return
func_type = function.type
if func_type.is_ptr:
func_type = func_type.base_type
self.type = func_type.return_type
class NotNode(ExprNode):
# 'not' operator
#
# operand ExprNode
type = PyrexTypes.c_bint_type
subexprs = ['operand']
def calculate_constant_result(self):
self.constant_result = not self.operand.constant_result
def compile_time_value(self, denv):
operand = self.operand.compile_time_value(denv)
try:
return not operand
except Exception, e:
self.compile_time_value_error(e)
def infer_type(self, env):
return PyrexTypes.c_bint_type
def analyse_types(self, env):
self.operand.analyse_types(env)
self.operand = self.operand.coerce_to_boolean(env)
def calculate_result_code(self):
return "(!%s)" % self.operand.result()
def generate_result_code(self, code):
pass
class UnaryPlusNode(UnopNode):
# unary '+' operator
operator = '+'
def analyse_c_operation(self, env):
self.type = self.operand.type
def py_operation_function(self):
return "PyNumber_Positive"
def calculate_result_code(self):
if self.is_cpp_operation():
return "(+%s)" % self.operand.result()
else:
return self.operand.result()
class UnaryMinusNode(UnopNode):
# unary '-' operator
operator = '-'
def analyse_c_operation(self, env):
if self.operand.type.is_numeric:
self.type = self.operand.type
else:
self.type_error()
if self.type.is_complex:
self.infix = False
def py_operation_function(self):
return "PyNumber_Negative"
def calculate_result_code(self):
if self.infix:
return "(-%s)" % self.operand.result()
else:
return "%s(%s)" % (self.operand.type.unary_op('-'), self.operand.result())
def get_constant_c_result_code(self):
value = self.operand.get_constant_c_result_code()
if value:
return "(-%s)" % (value)
class TildeNode(UnopNode):
# unary '~' operator
def analyse_c_operation(self, env):
if self.operand.type.is_int:
self.type = self.operand.type
else:
self.type_error()
def py_operation_function(self):
return "PyNumber_Invert"
def calculate_result_code(self):
return "(~%s)" % self.operand.result()
class CUnopNode(UnopNode):
def is_py_operation(self):
return False
class DereferenceNode(CUnopNode):
# unary * operator
operator = '*'
def analyse_c_operation(self, env):
if self.operand.type.is_ptr:
self.type = self.operand.type.base_type
else:
self.type_error()
def calculate_result_code(self):
return "(*%s)" % self.operand.result()
class DecrementIncrementNode(CUnopNode):
# unary ++/-- operator
def analyse_c_operation(self, env):
if self.operand.type.is_ptr or self.operand.type.is_numeric:
self.type = self.operand.type
else:
self.type_error()
def calculate_result_code(self):
if self.is_prefix:
return "(%s%s)" % (self.operator, self.operand.result())
else:
return "(%s%s)" % (self.operand.result(), self.operator)
def inc_dec_constructor(is_prefix, operator):
return lambda pos, **kwds: DecrementIncrementNode(pos, is_prefix=is_prefix, operator=operator, **kwds)
class AmpersandNode(ExprNode):
# The C address-of operator.
#
# operand ExprNode
subexprs = ['operand']
def infer_type(self, env):
return PyrexTypes.c_ptr_type(self.operand.infer_type(env))
def analyse_types(self, env):
self.operand.analyse_types(env)
argtype = self.operand.type
if not (argtype.is_cfunction or self.operand.is_lvalue()):
self.error("Taking address of non-lvalue")
return
if argtype.is_pyobject:
self.error("Cannot take address of Python variable")
return
self.type = PyrexTypes.c_ptr_type(argtype)
def check_const(self):
return self.operand.check_const_addr()
def error(self, mess):
error(self.pos, mess)
self.type = PyrexTypes.error_type
self.result_code = ""
def calculate_result_code(self):
return "(&%s)" % self.operand.result()
def generate_result_code(self, code):
pass
unop_node_classes = {
"+": UnaryPlusNode,
"-": UnaryMinusNode,
"~": TildeNode,
}
def unop_node(pos, operator, operand):
# Construct unnop node of appropriate class for
# given operator.
if isinstance(operand, IntNode) and operator == '-':
return IntNode(pos = operand.pos, value = str(-int(operand.value, 0)))
elif isinstance(operand, UnopNode) and operand.operator == operator:
warning(pos, "Python has no increment/decrement operator: %s%sx = %s(%sx) = x" % ((operator,)*4), 5)
return unop_node_classes[operator](pos,
operator = operator,
operand = operand)
class TypecastNode(ExprNode):
# C type cast
#
# operand ExprNode
# base_type CBaseTypeNode
# declarator CDeclaratorNode
#
# If used from a transform, one can if wanted specify the attribute
# "type" directly and leave base_type and declarator to None
subexprs = ['operand']
base_type = declarator = type = None
def type_dependencies(self, env):
return ()
def infer_type(self, env):
if self.type is None:
base_type = self.base_type.analyse(env)
_, self.type = self.declarator.analyse(base_type, env)
return self.type
def analyse_types(self, env):
if self.type is None:
base_type = self.base_type.analyse(env)
_, self.type = self.declarator.analyse(base_type, env)
if self.type.is_cfunction:
error(self.pos,
"Cannot cast to a function type")
self.type = PyrexTypes.error_type
self.operand.analyse_types(env)
to_py = self.type.is_pyobject
from_py = self.operand.type.is_pyobject
if from_py and not to_py and self.operand.is_ephemeral() and not self.type.is_numeric:
error(self.pos, "Casting temporary Python object to non-numeric non-Python type")
if to_py and not from_py:
if self.type is bytes_type and self.operand.type.is_int:
# FIXME: the type cast node isn't needed in this case
# and can be dropped once analyse_types() can return a
# different node
self.operand = 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_pyobject(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))
self.operand = self.operand.coerce_to_simple(env)
elif from_py and not to_py:
if self.type.create_from_py_utility_code(env):
self.operand = self.operand.coerce_to(self.type, env)
elif self.type.is_ptr:
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))
elif from_py and to_py:
if self.typecheck and self.type.is_extension_type:
self.operand = PyTypeTestNode(self.operand, self.type, env, notnone=True)
elif self.type.is_complex and self.operand.type.is_complex:
self.operand = self.operand.coerce_to_simple(env)
def nogil_check(self, env):
if self.type and self.type.is_pyobject and self.is_temp:
self.gil_error()
def check_const(self):
return self.operand.check_const()
def calculate_constant_result(self):
# we usually do not know the result of a type cast at code
# generation time
pass
def calculate_result_code(self):
if self.type.is_complex:
operand_result = self.operand.result()
if self.operand.type.is_complex:
real_part = self.type.real_type.cast_code("__Pyx_CREAL(%s)" % operand_result)
imag_part = self.type.real_type.cast_code("__Pyx_CIMAG(%s)" % operand_result)
else:
real_part = self.type.real_type.cast_code(operand_result)
imag_part = "0"
return "%s(%s, %s)" % (
self.type.from_parts,
real_part,
imag_part)
else:
return self.type.cast_code(self.operand.result())
def get_constant_c_result_code(self):
operand_result = self.operand.get_constant_c_result_code()
if operand_result:
return self.type.cast_code(operand_result)
def result_as(self, type):
if self.type.is_pyobject and not self.is_temp:
# Optimise away some unnecessary casting
return self.operand.result_as(type)
else:
return ExprNode.result_as(self, type)
def generate_result_code(self, code):
if self.is_temp:
code.putln(
"%s = (PyObject *)%s;" % (
self.result(),
self.operand.result()))
code.put_incref(self.result(), self.ctype())
class SizeofNode(ExprNode):
# Abstract base class for sizeof(x) expression nodes.
type = PyrexTypes.c_size_t_type
def check_const(self):
return True
def generate_result_code(self, code):
pass
class SizeofTypeNode(SizeofNode):
# C sizeof function applied to a type
#
# base_type CBaseTypeNode
# declarator CDeclaratorNode
subexprs = []
arg_type = None
def analyse_types(self, env):
# we may have incorrectly interpreted a dotted name as a type rather than an attribute
# this could be better handled by more uniformly treating types as runtime-available objects
if 0 and self.base_type.module_path:
path = self.base_type.module_path
obj = env.lookup(path[0])
if obj.as_module is None:
operand = NameNode(pos=self.pos, name=path[0])
for attr in path[1:]:
operand = AttributeNode(pos=self.pos, obj=operand, attribute=attr)
operand = AttributeNode(pos=self.pos, obj=operand, attribute=self.base_type.name)
self.operand = operand
self.__class__ = SizeofVarNode
self.analyse_types(env)
return
if self.arg_type is None:
base_type = self.base_type.analyse(env)
_, arg_type = self.declarator.analyse(base_type, env)
self.arg_type = arg_type
self.check_type()
def check_type(self):
arg_type = self.arg_type
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:
error(self.pos, "Cannot take sizeof void")
elif not arg_type.is_complete():
error(self.pos, "Cannot take sizeof incomplete type '%s'" % arg_type)
def calculate_result_code(self):
if self.arg_type.is_extension_type:
# the size of the pointer is boring
# we want the size of the actual struct
arg_code = self.arg_type.declaration_code("", deref=1)
else:
arg_code = self.arg_type.declaration_code("")
return "(sizeof(%s))" % arg_code
class SizeofVarNode(SizeofNode):
# C sizeof function applied to a variable
#
# operand ExprNode
subexprs = ['operand']
def analyse_types(self, env):
# We may actually be looking at a type rather than a variable...
# If we are, traditional analysis would fail...
operand_as_type = self.operand.analyse_as_type(env)
if operand_as_type:
self.arg_type = operand_as_type
self.__class__ = SizeofTypeNode
self.check_type()
else:
self.operand.analyse_types(env)
def calculate_result_code(self):
return "(sizeof(%s))" % self.operand.result()
def generate_result_code(self, code):
pass
class TypeofNode(ExprNode):
# Compile-time type of an expression, as a string.
#
# operand ExprNode
# literal StringNode # internal
literal = None
type = py_object_type
subexprs = ['literal'] # 'operand' will be ignored after type analysis!
def analyse_types(self, env):
self.operand.analyse_types(env)
self.literal = StringNode(
self.pos, value=StringEncoding.EncodedString(str(self.operand.type)))
self.literal.analyse_types(env)
self.literal = self.literal.coerce_to_pyobject(env)
def may_be_none(self):
return False
def generate_evaluation_code(self, code):
self.literal.generate_evaluation_code(code)
def calculate_result_code(self):
return self.literal.calculate_result_code()
#-------------------------------------------------------------------
#
# Binary operator nodes
#
#-------------------------------------------------------------------
def _not_in(x, seq):
return x not in seq
compile_time_binary_operators = {
'<': operator.lt,
'<=': operator.le,
'==': operator.eq,
'!=': operator.ne,
'>=': operator.ge,
'>': operator.gt,
'is': operator.is_,
'is_not': operator.is_not,
'+': operator.add,
'&': operator.and_,
'/': operator.truediv,
'//': operator.floordiv,
'<<': operator.lshift,
'%': operator.mod,
'*': operator.mul,
'|': operator.or_,
'**': operator.pow,
'>>': operator.rshift,
'-': operator.sub,
'^': operator.xor,
'in': operator.contains,
'not_in': _not_in,
}
def get_compile_time_binop(node):
func = compile_time_binary_operators.get(node.operator)
if not func:
error(node.pos,
"Binary '%s' not supported in compile-time expression"
% node.operator)
return func
class BinopNode(ExprNode):
# operator string
# operand1 ExprNode
# operand2 ExprNode
#
# Processing during analyse_expressions phase:
#
# analyse_c_operation
# Called when neither operand is a pyobject.
# - Check operand types and coerce if needed.
# - Determine result type and result code fragment.
# - Allocate temporary for result if needed.
subexprs = ['operand1', 'operand2']
def calculate_constant_result(self):
func = compile_time_binary_operators[self.operator]
self.constant_result = func(
self.operand1.constant_result,
self.operand2.constant_result)
def compile_time_value(self, denv):
func = get_compile_time_binop(self)
operand1 = self.operand1.compile_time_value(denv)
operand2 = self.operand2.compile_time_value(denv)
try:
return func(operand1, operand2)
except Exception, e:
self.compile_time_value_error(e)
def infer_type(self, env):
return self.result_type(self.operand1.infer_type(env),
self.operand2.infer_type(env))
def analyse_types(self, env):
self.operand1.analyse_types(env)
self.operand2.analyse_types(env)
if self.is_py_operation():
self.coerce_operands_to_pyobjects(env)
self.type = self.result_type(self.operand1.type,
self.operand2.type)
assert self.type.is_pyobject
self.is_temp = 1
elif self.is_cpp_operation():
self.analyse_cpp_operation(env)
else:
self.analyse_c_operation(env)
def is_py_operation(self):
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
def is_cpp_operation(self):
return (self.operand1.type.is_cpp_class
or self.operand2.type.is_cpp_class)
def analyse_cpp_operation(self, env):
type1 = self.operand1.type
type2 = self.operand2.type
entry = env.lookup_operator(self.operator, [self.operand1, self.operand2])
if not entry:
self.type_error()
return
func_type = entry.type
if func_type.is_ptr:
func_type = func_type.base_type
if len(func_type.args) == 1:
self.operand2 = self.operand2.coerce_to(func_type.args[0].type, env)
else:
self.operand1 = self.operand1.coerce_to(func_type.args[0].type, env)
self.operand2 = self.operand2.coerce_to(func_type.args[1].type, env)
self.type = func_type.return_type
def result_type(self, type1, type2):
if self.is_py_operation_types(type1, type2):
if type2.is_string:
type2 = Builtin.bytes_type
if type1.is_string:
type1 = Builtin.bytes_type
elif self.operator == '%' \
and type1 in (Builtin.str_type, Builtin.unicode_type):
# note that b'%s' % b'abc' doesn't work in Py3
return type1
if type1.is_builtin_type:
if type1 is type2:
if self.operator in '**%+|&^':
# FIXME: at least these operators should be safe - others?
return type1
elif self.operator == '*':
if type1 in (Builtin.bytes_type, Builtin.str_type, Builtin.unicode_type):
return type1
# multiplication of containers/numbers with an
# integer value always (?) returns the same type
if type2.is_int:
return type1
elif type2.is_builtin_type and type1.is_int and self.operator == '*':
# multiplication of containers/numbers with an
# integer value always (?) returns the same type
return type2
return py_object_type
else:
return self.compute_c_result_type(type1, type2)
def nogil_check(self, env):
if self.is_py_operation():
self.gil_error()
def coerce_operands_to_pyobjects(self, env):
self.operand1 = self.operand1.coerce_to_pyobject(env)
self.operand2 = self.operand2.coerce_to_pyobject(env)
def check_const(self):
return self.operand1.check_const() and self.operand2.check_const()
def generate_result_code(self, code):
#print "BinopNode.generate_result_code:", self.operand1, self.operand2 ###
if self.operand1.type.is_pyobject:
function = self.py_operation_function()
if function == "PyNumber_Power":
extra_args = ", Py_None"
else:
extra_args = ""
code.putln(
"%s = %s(%s, %s%s); %s" % (
self.result(),
function,
self.operand1.py_result(),
self.operand2.py_result(),
extra_args,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
def type_error(self):
if not (self.operand1.type.is_error
or self.operand2.type.is_error):
error(self.pos, "Invalid operand types for '%s' (%s; %s)" %
(self.operator, self.operand1.type,
self.operand2.type))
self.type = PyrexTypes.error_type
class CBinopNode(BinopNode):
def analyse_types(self, env):
BinopNode.analyse_types(self, env)
if self.is_py_operation():
self.type = PyrexTypes.error_type
def py_operation_function():
return ""
def calculate_result_code(self):
return "(%s %s %s)" % (
self.operand1.result(),
self.operator,
self.operand2.result())
def c_binop_constructor(operator):
def make_binop_node(pos, **operands):
return CBinopNode(pos, operator=operator, **operands)
return make_binop_node
class NumBinopNode(BinopNode):
# Binary operation taking numeric arguments.
infix = True
def analyse_c_operation(self, env):
type1 = self.operand1.type
type2 = self.operand2.type
self.type = self.compute_c_result_type(type1, type2)
if not self.type:
self.type_error()
return
if self.type.is_complex:
self.infix = False
if not self.infix or (type1.is_numeric and type2.is_numeric):
self.operand1 = self.operand1.coerce_to(self.type, env)
self.operand2 = self.operand2.coerce_to(self.type, env)
def compute_c_result_type(self, type1, type2):
if self.c_types_okay(type1, type2):
return PyrexTypes.widest_numeric_type(type1, type2)
else:
return None
def get_constant_c_result_code(self):
value1 = self.operand1.get_constant_c_result_code()
value2 = self.operand2.get_constant_c_result_code()
if value1 and value2:
return "(%s %s %s)" % (value1, self.operator, value2)
else:
return None
def c_types_okay(self, type1, type2):
#print "NumBinopNode.c_types_okay:", type1, type2 ###
return (type1.is_numeric or type1.is_enum) \
and (type2.is_numeric or type2.is_enum)
def calculate_result_code(self):
if self.infix:
return "(%s %s %s)" % (
self.operand1.result(),
self.operator,
self.operand2.result())
else:
func = self.type.binary_op(self.operator)
if func is None:
error(self.pos, "binary operator %s not supported for %s" % (self.operator, self.type))
return "%s(%s, %s)" % (
func,
self.operand1.result(),
self.operand2.result())
def is_py_operation_types(self, type1, type2):
return (type1 is PyrexTypes.c_py_unicode_type or
type2 is PyrexTypes.c_py_unicode_type or
BinopNode.is_py_operation_types(self, type1, type2))
def py_operation_function(self):
return self.py_functions[self.operator]
py_functions = {
"|": "PyNumber_Or",
"^": "PyNumber_Xor",
"&": "PyNumber_And",
"<<": "PyNumber_Lshift",
">>": "PyNumber_Rshift",
"+": "PyNumber_Add",
"-": "PyNumber_Subtract",
"*": "PyNumber_Multiply",
"/": "__Pyx_PyNumber_Divide",
"//": "PyNumber_FloorDivide",
"%": "PyNumber_Remainder",
"**": "PyNumber_Power"
}
class IntBinopNode(NumBinopNode):
# Binary operation taking integer arguments.
def c_types_okay(self, type1, type2):
#print "IntBinopNode.c_types_okay:", type1, type2 ###
return (type1.is_int or type1.is_enum) \
and (type2.is_int or type2.is_enum)
class AddNode(NumBinopNode):
# '+' operator.
def is_py_operation_types(self, type1, type2):
if type1.is_string and type2.is_string:
return 1
else:
return NumBinopNode.is_py_operation_types(self, type1, type2)
def compute_c_result_type(self, type1, type2):
#print "AddNode.compute_c_result_type:", type1, self.operator, type2 ###
if (type1.is_ptr or type1.is_array) and (type2.is_int or type2.is_enum):
return type1
elif (type2.is_ptr or type2.is_array) and (type1.is_int or type1.is_enum):
return type2
else:
return NumBinopNode.compute_c_result_type(
self, type1, type2)
class SubNode(NumBinopNode):
# '-' operator.
def compute_c_result_type(self, type1, type2):
if (type1.is_ptr or type1.is_array) and (type2.is_int or type2.is_enum):
return type1
elif (type1.is_ptr or type1.is_array) and (type2.is_ptr or type2.is_array):
return PyrexTypes.c_int_type
else:
return NumBinopNode.compute_c_result_type(
self, type1, type2)
class MulNode(NumBinopNode):
# '*' operator.
def is_py_operation_types(self, type1, type2):
if (type1.is_string and type2.is_int) \
or (type2.is_string and type1.is_int):
return 1
else:
return NumBinopNode.is_py_operation_types(self, type1, type2)
class DivNode(NumBinopNode):
# '/' or '//' operator.
cdivision = None
truedivision = None # == "unknown" if operator == '/'
ctruedivision = False
cdivision_warnings = False
zerodivision_check = None
def find_compile_time_binary_operator(self, op1, op2):
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, (int,long)) and isinstance(op2, (int,long)):
func = compile_time_binary_operators['//']
return func
def calculate_constant_result(self):
op1 = self.operand1.constant_result
op2 = self.operand2.constant_result
func = self.find_compile_time_binary_operator(op1, op2)
self.constant_result = func(
self.operand1.constant_result,
self.operand2.constant_result)
def compile_time_value(self, denv):
operand1 = self.operand1.compile_time_value(denv)
operand2 = self.operand2.compile_time_value(denv)
try:
func = self.find_compile_time_binary_operator(
self, operand1, operand2)
return func(operand1, operand2)
except Exception, e:
self.compile_time_value_error(e)
def analyse_types(self, env):
if self.cdivision or env.directives['cdivision']:
self.ctruedivision = False
else:
self.ctruedivision = self.truedivision
NumBinopNode.analyse_types(self, env)
if self.is_cpp_operation():
self.cdivision = True
if not self.type.is_pyobject:
self.zerodivision_check = (
self.cdivision is None and not env.directives['cdivision']
and (not self.operand2.has_constant_result() or
self.operand2.constant_result == 0))
if self.zerodivision_check or env.directives['cdivision_warnings']:
# Need to check ahead of time to warn or raise zero division error
self.operand1 = self.operand1.coerce_to_simple(env)
self.operand2 = self.operand2.coerce_to_simple(env)
if env.nogil:
error(self.pos, "Pythonic division not allowed without gil, consider using cython.cdivision(True)")
def compute_c_result_type(self, type1, type2):
if self.operator == '/' and self.ctruedivision:
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)
return widest_type
return NumBinopNode.compute_c_result_type(self, type1, type2)
def zero_division_message(self):
if self.type.is_int:
return "integer division or modulo by zero"
else:
return "float division"
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 not self.type.signed
or self.type.is_float)
if not self.cdivision:
code.globalstate.use_utility_code(div_int_utility_code.specialize(self.type))
NumBinopNode.generate_evaluation_code(self, code)
self.generate_div_warning_code(code)
def generate_div_warning_code(self, code):
if not self.type.is_pyobject:
if self.zerodivision_check:
if not self.infix:
zero_test = "%s(%s)" % (self.type.unary_op('zero'), self.operand2.result())
else:
zero_test = "%s == 0" % self.operand2.result()
code.putln("if (unlikely(%s)) {" % zero_test)
code.putln('PyErr_Format(PyExc_ZeroDivisionError, "%s");' % self.zero_division_message())
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(division_overflow_test_code)
code.putln("else if (sizeof(%s) == sizeof(long) && unlikely(%s == -1) && unlikely(UNARY_NEG_WOULD_OVERFLOW(%s))) {" % (
self.type.declaration_code(''),
self.operand2.result(),
self.operand1.result()))
code.putln('PyErr_Format(PyExc_OverflowError, "value too large to perform division");')
code.putln(code.error_goto(self.pos))
code.putln("}")
if code.globalstate.directives['cdivision_warnings'] and self.operator != '/':
code.globalstate.use_utility_code(cdivision_warning_utility_code)
code.putln("if ((%s < 0) ^ (%s < 0)) {" % (
self.operand1.result(),
self.operand2.result()))
code.putln(code.set_error_info(self.pos));
code.put("if (__Pyx_cdivision_warning()) ")
code.put_goto(code.error_label)
code.putln("}")
def calculate_result_code(self):
if self.type.is_complex:
return NumBinopNode.calculate_result_code(self)
elif self.type.is_float and self.operator == '//':
return "floor(%s / %s)" % (
self.operand1.result(),
self.operand2.result())
elif self.truedivision or self.cdivision:
op1 = self.operand1.result()
op2 = self.operand2.result()
if self.truedivision:
if self.type != self.operand1.type:
op1 = self.type.cast_code(op1)
if self.type != self.operand2.type:
op2 = self.type.cast_code(op2)
return "(%s / %s)" % (op1, op2)
else:
return "__Pyx_div_%s(%s, %s)" % (
self.type.specialization_name(),
self.operand1.result(),
self.operand2.result())
class ModNode(DivNode):
# '%' operator.
def is_py_operation_types(self, type1, type2):
return (type1.is_string
or type2.is_string
or NumBinopNode.is_py_operation_types(self, type1, type2))
def zero_division_message(self):
if self.type.is_int:
return "integer division or modulo by zero"
else:
return "float divmod()"
def generate_evaluation_code(self, code):
if not self.type.is_pyobject:
if self.cdivision is None:
self.cdivision = code.globalstate.directives['cdivision'] or not self.type.signed
if not self.cdivision:
if self.type.is_int:
code.globalstate.use_utility_code(mod_int_utility_code.specialize(self.type))
else:
code.globalstate.use_utility_code(
mod_float_utility_code.specialize(self.type, math_h_modifier=self.type.math_h_modifier))
NumBinopNode.generate_evaluation_code(self, code)
self.generate_div_warning_code(code)
def calculate_result_code(self):
if self.cdivision:
if self.type.is_float:
return "fmod%s(%s, %s)" % (
self.type.math_h_modifier,
self.operand1.result(),
self.operand2.result())
else:
return "(%s %% %s)" % (
self.operand1.result(),
self.operand2.result())
else:
return "__Pyx_mod_%s(%s, %s)" % (
self.type.specialization_name(),
self.operand1.result(),
self.operand2.result())
class PowNode(NumBinopNode):
# '**' operator.
def analyse_c_operation(self, env):
NumBinopNode.analyse_c_operation(self, env)
if self.type.is_complex:
error(self.pos, "complex powers not yet supported")
self.pow_func = ""
elif self.type.is_float:
self.pow_func = "pow"
else:
self.pow_func = "__Pyx_pow_%s" % self.type.declaration_code('').replace(' ', '_')
env.use_utility_code(
int_pow_utility_code.specialize(func_name=self.pow_func,
type=self.type.declaration_code('')))
def calculate_result_code(self):
return "%s(%s, %s)" % (
self.pow_func,
self.operand1.result(),
self.operand2.result())
# Note: This class is temporarily "shut down" into an ineffective temp
# allocation mode.
#
# More sophisticated temp reuse was going on before, one could have a
# look at adding this again after /all/ classes are converted to the
# new temp scheme. (The temp juggling cannot work otherwise).
class BoolBinopNode(ExprNode):
# Short-circuiting boolean operation.
#
# operator string
# operand1 ExprNode
# operand2 ExprNode
subexprs = ['operand1', 'operand2']
def infer_type(self, env):
type1 = self.operand1.infer_type(env)
type2 = self.operand2.infer_type(env)
return PyrexTypes.independent_spanning_type(type1, type2)
def may_be_none(self):
if self.operator == 'or':
return self.operand2.may_be_none()
else:
return self.operand1.may_be_none() or self.operand2.may_be_none()
def calculate_constant_result(self):
if self.operator == 'and':
self.constant_result = \
self.operand1.constant_result and \
self.operand2.constant_result
else:
self.constant_result = \
self.operand1.constant_result or \
self.operand2.constant_result
def compile_time_value(self, denv):
if self.operator == 'and':
return self.operand1.compile_time_value(denv) \
and self.operand2.compile_time_value(denv)
else:
return self.operand1.compile_time_value(denv) \
or self.operand2.compile_time_value(denv)
def coerce_to_boolean(self, env):
return BoolBinopNode(
self.pos,
operator = self.operator,
operand1 = self.operand1.coerce_to_boolean(env),
operand2 = self.operand2.coerce_to_boolean(env),
type = PyrexTypes.c_bint_type,
is_temp = self.is_temp)
def analyse_types(self, env):
self.operand1.analyse_types(env)
self.operand2.analyse_types(env)
self.type = PyrexTypes.independent_spanning_type(self.operand1.type, self.operand2.type)
self.operand1 = self.operand1.coerce_to(self.type, env)
self.operand2 = self.operand2.coerce_to(self.type, env)
# For what we're about to do, it's vital that
# both operands be temp nodes.
self.operand1 = self.operand1.coerce_to_simple(env)
self.operand2 = self.operand2.coerce_to_simple(env)
self.is_temp = 1
gil_message = "Truth-testing Python object"
def check_const(self):
return self.operand1.check_const() and self.operand2.check_const()
def generate_evaluation_code(self, code):
code.mark_pos(self.pos)
self.operand1.generate_evaluation_code(code)
test_result, uses_temp = self.generate_operand1_test(code)
if self.operator == 'and':
sense = ""
else:
sense = "!"
code.putln(
"if (%s%s) {" % (
sense,
test_result))
if uses_temp:
code.funcstate.release_temp(test_result)
self.operand1.generate_disposal_code(code)
self.operand2.generate_evaluation_code(code)
self.allocate_temp_result(code)
self.operand2.make_owned_reference(code)
code.putln("%s = %s;" % (self.result(), self.operand2.result()))
self.operand2.generate_post_assignment_code(code)
self.operand2.free_temps(code)
code.putln("} else {")
self.operand1.make_owned_reference(code)
code.putln("%s = %s;" % (self.result(), self.operand1.result()))
self.operand1.generate_post_assignment_code(code)
self.operand1.free_temps(code)
code.putln("}")
def generate_operand1_test(self, code):
# Generate code to test the truth of the first operand.
if self.type.is_pyobject:
test_result = code.funcstate.allocate_temp(PyrexTypes.c_bint_type,
manage_ref=False)
code.putln(
"%s = __Pyx_PyObject_IsTrue(%s); %s" % (
test_result,
self.operand1.py_result(),
code.error_goto_if_neg(test_result, self.pos)))
else:
test_result = self.operand1.result()
return (test_result, self.type.is_pyobject)
class CondExprNode(ExprNode):
# Short-circuiting conditional expression.
#
# test ExprNode
# true_val ExprNode
# false_val ExprNode
true_val = None
false_val = None
subexprs = ['test', 'true_val', 'false_val']
def type_dependencies(self, env):
return self.true_val.type_dependencies(env) + self.false_val.type_dependencies(env)
def infer_type(self, env):
return PyrexTypes.independent_spanning_type(self.true_val.infer_type(env),
self.false_val.infer_type(env))
def calculate_constant_result(self):
if self.test.constant_result:
self.constant_result = self.true_val.constant_result
else:
self.constant_result = self.false_val.constant_result
def analyse_types(self, env):
self.test.analyse_types(env)
self.test = self.test.coerce_to_boolean(env)
self.true_val.analyse_types(env)
self.false_val.analyse_types(env)
self.type = PyrexTypes.independent_spanning_type(self.true_val.type, self.false_val.type)
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)
self.is_temp = 1
if self.type == PyrexTypes.error_type:
self.type_error()
def type_error(self):
if not (self.true_val.type.is_error or self.false_val.type.is_error):
error(self.pos, "Incompatable types in conditional expression (%s; %s)" %
(self.true_val.type, self.false_val.type))
self.type = PyrexTypes.error_type
def check_const(self):
return (self.test.check_const()
and self.true_val.check_const()
and self.false_val.check_const())
def generate_evaluation_code(self, code):
# Because subexprs may not be evaluated we can use a more optimal
# subexpr allocation strategy than the default, so override evaluation_code.
code.mark_pos(self.pos)
self.allocate_temp_result(code)
self.test.generate_evaluation_code(code)
code.putln("if (%s) {" % self.test.result() )
self.eval_and_get(code, self.true_val)
code.putln("} else {")
self.eval_and_get(code, self.false_val)
code.putln("}")
self.test.generate_disposal_code(code)
self.test.free_temps(code)
def eval_and_get(self, code, expr):
expr.generate_evaluation_code(code)
expr.make_owned_reference(code)
code.putln("%s = %s;" % (self.result(), expr.result()))
expr.generate_post_assignment_code(code)
expr.free_temps(code)
richcmp_constants = {
"<" : "Py_LT",
"<=": "Py_LE",
"==": "Py_EQ",
"!=": "Py_NE",
"<>": "Py_NE",
">" : "Py_GT",
">=": "Py_GE",
}
class CmpNode(object):
# Mixin class containing code common to PrimaryCmpNodes
# and CascadedCmpNodes.
def infer_type(self, env):
# TODO: Actually implement this (after merging with -unstable).
return py_object_type
def calculate_cascaded_constant_result(self, operand1_result):
func = compile_time_binary_operators[self.operator]
operand2_result = self.operand2.constant_result
result = func(operand1_result, operand2_result)
if self.cascade:
self.cascade.calculate_cascaded_constant_result(operand2_result)
if self.cascade.constant_result:
self.constant_result = result and self.cascade.constant_result
else:
self.constant_result = result
def cascaded_compile_time_value(self, operand1, denv):
func = get_compile_time_binop(self)
operand2 = self.operand2.compile_time_value(denv)
try:
result = func(operand1, operand2)
except Exception, e:
self.compile_time_value_error(e)
result = None
if result:
cascade = self.cascade
if cascade:
# FIXME: I bet this must call cascaded_compile_time_value()
result = result and cascade.cascaded_compile_time_value(operand2, denv)
return result
def is_cpp_comparison(self):
return self.operand1.type.is_cpp_class or self.operand2.type.is_cpp_class
def find_common_int_type(self, env, op, operand1, operand2):
# type1 != type2 and at least one of the types is not a C int
type1 = operand1.type
type2 = operand2.type
type1_can_be_int = False
type2_can_be_int = False
if isinstance(operand1, (StringNode, BytesNode, UnicodeNode)) \
and operand1.can_coerce_to_char_literal():
type1_can_be_int = True
if isinstance(operand2, (StringNode, BytesNode, UnicodeNode)) \
and operand2.can_coerce_to_char_literal():
type2_can_be_int = True
if type1.is_int:
if type2_can_be_int:
return type1
elif type2.is_int:
if type1_can_be_int:
return type2
elif type1_can_be_int:
if type2_can_be_int:
return PyrexTypes.c_uchar_type
return None
def find_common_type(self, env, op, operand1, common_type=None):
operand2 = self.operand2
type1 = operand1.type
type2 = operand2.type
new_common_type = None
# catch general errors
if type1 == str_type and (type2.is_string or type2 in (bytes_type, unicode_type)) or \
type2 == str_type and (type1.is_string or type1 in (bytes_type, unicode_type)):
error(self.pos, "Comparisons between bytes/unicode and str are not portable to Python 3")
new_common_type = error_type
# try to use numeric comparisons where possible
elif type1.is_complex or type2.is_complex:
if op not in ('==', '!='):
error(self.pos, "complex types are unordered")
new_common_type = error_type
if type1.is_pyobject:
new_common_type = type1
elif type2.is_pyobject:
new_common_type = type2
else:
new_common_type = PyrexTypes.widest_numeric_type(type1, type2)
elif type1.is_numeric and type2.is_numeric:
new_common_type = PyrexTypes.widest_numeric_type(type1, type2)
elif common_type is None or not common_type.is_pyobject:
new_common_type = self.find_common_int_type(env, op, operand1, operand2)
if new_common_type is None:
# fall back to generic type compatibility tests
if type1 == type2:
new_common_type = type1
elif type1.is_pyobject or type2.is_pyobject:
if type2.is_numeric or type2.is_string:
if operand2.check_for_coercion_error(type1):
new_common_type = error_type
else:
new_common_type = py_object_type
elif type1.is_numeric or type1.is_string:
if operand1.check_for_coercion_error(type2):
new_common_type = error_type
else:
new_common_type = py_object_type
elif py_object_type.assignable_from(type1) and py_object_type.assignable_from(type2):
new_common_type = py_object_type
else:
# one Python type and one non-Python type, not assignable
self.invalid_types_error(operand1, op, operand2)
new_common_type = error_type
elif type1.assignable_from(type2):
new_common_type = type1
elif type2.assignable_from(type1):
new_common_type = type2
else:
# C types that we couldn't handle up to here are an error
self.invalid_types_error(operand1, op, operand2)
new_common_type = error_type
# recursively merge types
if common_type is None or new_common_type.is_error:
common_type = new_common_type
else:
# we could do a lot better by splitting the comparison
# into a non-Python part and a Python part, but this is
# safer for now
common_type = PyrexTypes.spanning_type(common_type, new_common_type)
if self.cascade:
common_type = self.cascade.find_common_type(env, self.operator, operand2, common_type)
return common_type
def invalid_types_error(self, operand1, op, operand2):
error(self.pos, "Invalid types for '%s' (%s, %s)" %
(op, operand1.type, operand2.type))
def is_python_comparison(self):
return (not self.is_ptr_contains()
and not self.is_c_string_contains()
and (self.has_python_operands()
or (self.cascade and self.cascade.is_python_comparison())
or self.operator in ('in', 'not_in')))
def coerce_operands_to(self, dst_type, env):
operand2 = self.operand2
if operand2.type != dst_type:
self.operand2 = operand2.coerce_to(dst_type, env)
if self.cascade:
self.cascade.coerce_operands_to(dst_type, env)
def is_python_result(self):
return ((self.has_python_operands() and
self.operator not in ('is', 'is_not', 'in', 'not_in') and
not self.is_c_string_contains() and
not self.is_ptr_contains())
or (self.cascade and self.cascade.is_python_result()))
def is_c_string_contains(self):
return self.operator in ('in', 'not_in') and \
((self.operand1.type.is_int
and (self.operand2.type.is_string or self.operand2.type is bytes_type)) or
(self.operand1.type is PyrexTypes.c_py_unicode_type
and self.operand2.type is unicode_type))
def is_ptr_contains(self):
if self.operator in ('in', 'not_in'):
container_type = self.operand2.type
return (container_type.is_ptr or container_type.is_array) \
and not container_type.is_string
def generate_operation_code(self, code, result_code,
operand1, op , operand2):
if self.type.is_pyobject:
coerce_result = "__Pyx_PyBool_FromLong"
else:
coerce_result = ""
if 'not' in op:
negation = "!"
else:
negation = ""
if op == 'in' or op == 'not_in':
code.globalstate.use_utility_code(contains_utility_code)
if self.type.is_pyobject:
coerce_result = "__Pyx_PyBoolOrNull_FromLong"
if op == 'not_in':
negation = "__Pyx_NegateNonNeg"
if operand2.type is dict_type:
code.globalstate.use_utility_code(
raise_none_iter_error_utility_code)
code.putln("if (unlikely(%s == Py_None)) {" % operand2.py_result())
code.putln("__Pyx_RaiseNoneNotIterableError(); %s" %
code.error_goto(self.pos))
code.putln("} else {")
method = "PyDict_Contains"
else:
method = "PySequence_Contains"
if self.type.is_pyobject:
error_clause = code.error_goto_if_null
got_ref = "__Pyx_XGOTREF(%s); " % result_code
else:
error_clause = code.error_goto_if_neg
got_ref = ""
code.putln(
"%s = %s(%s(%s(%s, %s))); %s%s" % (
result_code,
coerce_result,
negation,
method,
operand2.py_result(),
operand1.py_result(),
got_ref,
error_clause(result_code, self.pos)))
if operand2.type is dict_type:
code.putln("}")
elif (operand1.type.is_pyobject
and op not in ('is', 'is_not')):
code.putln("%s = PyObject_RichCompare(%s, %s, %s); %s" % (
result_code,
operand1.py_result(),
operand2.py_result(),
richcmp_constants[op],
code.error_goto_if_null(result_code, self.pos)))
code.put_gotref(result_code)
elif operand1.type.is_complex:
if op == "!=":
negation = "!"
else:
negation = ""
code.putln("%s = %s(%s%s(%s, %s));" % (
result_code,
coerce_result,
negation,
operand1.type.unary_op('eq'),
operand1.result(),
operand2.result()))
else:
type1 = operand1.type
type2 = operand2.type
if (type1.is_extension_type or type2.is_extension_type) \
and not type1.same_as(type2):
common_type = py_object_type
elif type1.is_numeric:
common_type = PyrexTypes.widest_numeric_type(type1, type2)
else:
common_type = type1
code1 = operand1.result_as(common_type)
code2 = operand2.result_as(common_type)
code.putln("%s = %s(%s %s %s);" % (
result_code,
coerce_result,
code1,
self.c_operator(op),
code2))
def c_operator(self, op):
if op == 'is':
return "=="
elif op == 'is_not':
return "!="
else:
return op
contains_utility_code = UtilityCode(
proto="""
static CYTHON_INLINE long __Pyx_NegateNonNeg(long b) { return unlikely(b < 0) ? b : !b; }
static CYTHON_INLINE PyObject* __Pyx_PyBoolOrNull_FromLong(long b) {
return unlikely(b < 0) ? NULL : __Pyx_PyBool_FromLong(b);
}
""")
char_in_bytes_utility_code = UtilityCode(
proto="""
static CYTHON_INLINE int __Pyx_BytesContains(PyObject* bytes, char character); /*proto*/
""",
impl="""
static CYTHON_INLINE int __Pyx_BytesContains(PyObject* bytes, char character) {
const Py_ssize_t length = PyBytes_GET_SIZE(bytes);
char* char_start = PyBytes_AS_STRING(bytes);
char* pos;
for (pos=char_start; pos < char_start+length; pos++) {
if (character == pos[0]) return 1;
}
return 0;
}
""")
pyunicode_in_unicode_utility_code = UtilityCode(
proto="""
static CYTHON_INLINE int __Pyx_UnicodeContains(PyObject* unicode, Py_UNICODE character); /*proto*/
""",
impl="""
static CYTHON_INLINE int __Pyx_UnicodeContains(PyObject* unicode, Py_UNICODE character) {
const Py_ssize_t length = PyUnicode_GET_SIZE(unicode);
Py_UNICODE* char_start = PyUnicode_AS_UNICODE(unicode);
Py_UNICODE* pos;
for (pos=char_start; pos < char_start+length; pos++) {
if (character == pos[0]) return 1;
}
return 0;
}
""")
class PrimaryCmpNode(ExprNode, CmpNode):
# Non-cascaded comparison or first comparison of
# a cascaded sequence.
#
# operator string
# operand1 ExprNode
# operand2 ExprNode
# cascade CascadedCmpNode
# We don't use the subexprs mechanism, because
# things here are too complicated for it to handle.
# Instead, we override all the framework methods
# which use it.
child_attrs = ['operand1', 'operand2', 'cascade']
cascade = None
def infer_type(self, env):
# TODO: Actually implement this (after merging with -unstable).
return py_object_type
def type_dependencies(self, env):
return ()
def calculate_constant_result(self):
self.calculate_cascaded_constant_result(self.operand1.constant_result)
def compile_time_value(self, denv):
operand1 = self.operand1.compile_time_value(denv)
return self.cascaded_compile_time_value(operand1, denv)
def analyse_types(self, env):
self.operand1.analyse_types(env)
self.operand2.analyse_types(env)
if self.is_cpp_comparison():
self.analyse_cpp_comparison(env)
if self.cascade:
error(self.pos, "Cascading comparison not yet supported for cpp types.")
return
if self.cascade:
self.cascade.analyse_types(env)
if self.operator in ('in', 'not_in'):
if self.is_c_string_contains():
self.is_pycmp = False
common_type = None
if self.cascade:
error(self.pos, "Cascading comparison not yet supported for 'int_val in string'.")
return
if self.operand2.type is unicode_type:
env.use_utility_code(pyunicode_in_unicode_utility_code)
else:
if self.operand1.type is PyrexTypes.c_uchar_type:
self.operand1 = self.operand1.coerce_to(PyrexTypes.c_char_type, env)
if self.operand2.type is not bytes_type:
self.operand2 = self.operand2.coerce_to(bytes_type, env)
env.use_utility_code(char_in_bytes_utility_code)
self.operand2 = self.operand2.as_none_safe_node(
"argument of type 'NoneType' is not iterable")
elif self.is_ptr_contains():
if self.cascade:
error(self.pos, "Cascading comparison not yet supported for 'val in sliced pointer'.")
self.type = PyrexTypes.c_bint_type
# Will be transformed by IterationTransform
return
else:
common_type = py_object_type
self.is_pycmp = True
else:
common_type = self.find_common_type(env, self.operator, self.operand1)
self.is_pycmp = common_type.is_pyobject
if common_type is not None and not common_type.is_error:
if self.operand1.type != common_type:
self.operand1 = self.operand1.coerce_to(common_type, env)
self.coerce_operands_to(common_type, env)
if self.cascade:
self.operand2 = self.operand2.coerce_to_simple(env)
self.cascade.coerce_cascaded_operands_to_temp(env)
if self.is_python_result():
self.type = PyrexTypes.py_object_type
else:
self.type = PyrexTypes.c_bint_type
cdr = self.cascade
while cdr:
cdr.type = self.type
cdr = cdr.cascade
if self.is_pycmp or self.cascade:
self.is_temp = 1
def analyse_cpp_comparison(self, env):
type1 = self.operand1.type
type2 = self.operand2.type
entry = env.lookup_operator(self.operator, [self.operand1, self.operand2])
if entry is None:
error(self.pos, "Invalid types for '%s' (%s, %s)" %
(self.operator, type1, type2))
self.type = PyrexTypes.error_type
self.result_code = ""
return
func_type = entry.type
if func_type.is_ptr:
func_type = func_type.base_type
if len(func_type.args) == 1:
self.operand2 = self.operand2.coerce_to(func_type.args[0].type, env)
else:
self.operand1 = self.operand1.coerce_to(func_type.args[0].type, env)
self.operand2 = self.operand2.coerce_to(func_type.args[1].type, env)
self.type = func_type.return_type
def has_python_operands(self):
return (self.operand1.type.is_pyobject
or self.operand2.type.is_pyobject)
def check_const(self):
if self.cascade:
self.not_const()
return False
else:
return self.operand1.check_const() and self.operand2.check_const()
def calculate_result_code(self):
if self.operand1.type.is_complex:
if self.operator == "!=":
negation = "!"
else:
negation = ""
return "(%s%s(%s, %s))" % (
negation,
self.operand1.type.binary_op('=='),
self.operand1.result(),
self.operand2.result())
elif self.is_c_string_contains():
if self.operand2.type is bytes_type:
method = "__Pyx_BytesContains"
else:
method = "__Pyx_UnicodeContains"
if self.operator == "not_in":
negation = "!"
else:
negation = ""
return "(%s%s(%s, %s))" % (
negation,
method,
self.operand2.result(),
self.operand1.result())
else:
return "(%s %s %s)" % (
self.operand1.result(),
self.c_operator(self.operator),
self.operand2.result())
def generate_evaluation_code(self, code):
self.operand1.generate_evaluation_code(code)
self.operand2.generate_evaluation_code(code)
if self.is_temp:
self.allocate_temp_result(code)
self.generate_operation_code(code, self.result(),
self.operand1, self.operator, self.operand2)
if self.cascade:
self.cascade.generate_evaluation_code(code,
self.result(), self.operand2)
self.operand1.generate_disposal_code(code)
self.operand1.free_temps(code)
self.operand2.generate_disposal_code(code)
self.operand2.free_temps(code)
def generate_subexpr_disposal_code(self, code):
# If this is called, it is a non-cascaded cmp,
# so only need to dispose of the two main operands.
self.operand1.generate_disposal_code(code)
self.operand2.generate_disposal_code(code)
def free_subexpr_temps(self, code):
# If this is called, it is a non-cascaded cmp,
# so only need to dispose of the two main operands.
self.operand1.free_temps(code)
self.operand2.free_temps(code)
def annotate(self, code):
self.operand1.annotate(code)
self.operand2.annotate(code)
if self.cascade:
self.cascade.annotate(code)
class CascadedCmpNode(Node, CmpNode):
# A CascadedCmpNode is not a complete expression node. It
# hangs off the side of another comparison node, shares
# its left operand with that node, and shares its result
# with the PrimaryCmpNode at the head of the chain.
#
# operator string
# operand2 ExprNode
# cascade CascadedCmpNode
child_attrs = ['operand2', 'cascade']
cascade = None
constant_result = constant_value_not_set # FIXME: where to calculate this?
def infer_type(self, env):
# TODO: Actually implement this (after merging with -unstable).
return py_object_type
def type_dependencies(self, env):
return ()
def has_constant_result(self):
return self.constant_result is not constant_value_not_set and \
self.constant_result is not not_a_constant
def analyse_types(self, env):
self.operand2.analyse_types(env)
if self.cascade:
self.cascade.analyse_types(env)
def has_python_operands(self):
return self.operand2.type.is_pyobject
def coerce_operands_to_pyobjects(self, env):
self.operand2 = self.operand2.coerce_to_pyobject(env)
if self.cascade:
self.cascade.coerce_operands_to_pyobjects(env)
def coerce_cascaded_operands_to_temp(self, env):
if self.cascade:
#self.operand2 = self.operand2.coerce_to_temp(env) #CTT
self.operand2 = self.operand2.coerce_to_simple(env)
self.cascade.coerce_cascaded_operands_to_temp(env)
def generate_evaluation_code(self, code, result, operand1):
if self.type.is_pyobject:
code.putln("if (__Pyx_PyObject_IsTrue(%s)) {" % result)
code.put_decref(result, self.type)
else:
code.putln("if (%s) {" % result)
self.operand2.generate_evaluation_code(code)
self.generate_operation_code(code, result,
operand1, self.operator, self.operand2)
if self.cascade:
self.cascade.generate_evaluation_code(
code, result, self.operand2)
# Cascaded cmp result is always temp
self.operand2.generate_disposal_code(code)
self.operand2.free_temps(code)
code.putln("}")
def annotate(self, code):
self.operand2.annotate(code)
if self.cascade:
self.cascade.annotate(code)
binop_node_classes = {
"or": BoolBinopNode,
"and": BoolBinopNode,
"|": IntBinopNode,
"^": IntBinopNode,
"&": IntBinopNode,
"<<": IntBinopNode,
">>": IntBinopNode,
"+": AddNode,
"-": SubNode,
"*": MulNode,
"/": DivNode,
"//": DivNode,
"%": ModNode,
"**": PowNode
}
def binop_node(pos, operator, operand1, operand2):
# Construct binop node of appropriate class for
# given operator.
return binop_node_classes[operator](pos,
operator = operator,
operand1 = operand1,
operand2 = operand2)
#-------------------------------------------------------------------
#
# Coercion nodes
#
# Coercion nodes are special in that they are created during
# the analyse_types phase of parse tree processing.
# Their __init__ methods consequently incorporate some aspects
# of that phase.
#
#-------------------------------------------------------------------
class CoercionNode(ExprNode):
# Abstract base class for coercion nodes.
#
# arg ExprNode node being coerced
subexprs = ['arg']
constant_result = not_a_constant
def __init__(self, arg):
self.pos = arg.pos
self.arg = arg
if debug_coercion:
print("%s Coercing %s" % (self, self.arg))
def calculate_constant_result(self):
# constant folding can break type coercion, so this is disabled
pass
def annotate(self, code):
self.arg.annotate(code)
if self.arg.type != self.type:
file, line, col = self.pos
code.annotate((file, line, col-1), AnnotationItem(style='coerce', tag='coerce', text='[%s] to [%s]' % (self.arg.type, self.type)))
class CastNode(CoercionNode):
# Wrap a node in a C type cast.
def __init__(self, arg, new_type):
CoercionNode.__init__(self, arg)
self.type = new_type
def may_be_none(self):
return self.arg.may_be_none()
def calculate_result_code(self):
return self.arg.result_as(self.type)
def generate_result_code(self, code):
self.arg.generate_result_code(code)
class PyTypeTestNode(CoercionNode):
# This node is used to check that a generic Python
# object is an instance of a particular extension type.
# This node borrows the result of its argument node.
def __init__(self, arg, dst_type, env, notnone=False):
# The arg is know to be a Python object, and
# the dst_type is known to be an extension type.
assert dst_type.is_extension_type or dst_type.is_builtin_type, "PyTypeTest on non extension type"
CoercionNode.__init__(self, arg)
self.type = dst_type
self.result_ctype = arg.ctype()
self.notnone = notnone
nogil_check = Node.gil_error
gil_message = "Python type test"
def analyse_types(self, env):
pass
def may_be_none(self):
if self.notnone:
return False
return self.arg.may_be_none()
def result_in_temp(self):
return self.arg.result_in_temp()
def is_ephemeral(self):
return self.arg.is_ephemeral()
def calculate_constant_result(self):
# FIXME
pass
def calculate_result_code(self):
return self.arg.result()
def generate_result_code(self, code):
if self.type.typeobj_is_available():
if not self.type.is_builtin_type:
code.globalstate.use_utility_code(type_test_utility_code)
code.putln(
"if (!(%s)) %s" % (
self.type.type_test_code(self.arg.py_result(), self.notnone),
code.error_goto(self.pos)))
else:
error(self.pos, "Cannot test type of extern C class "
"without type object name specification")
def generate_post_assignment_code(self, code):
self.arg.generate_post_assignment_code(code)
def free_temps(self, code):
self.arg.free_temps(code)
class NoneCheckNode(CoercionNode):
# This node is used to check that a Python object is not None and
# raises an appropriate exception (as specified by the creating
# transform).
def __init__(self, arg, exception_type_cname, exception_message):
CoercionNode.__init__(self, arg)
self.type = arg.type
self.result_ctype = arg.ctype()
self.exception_type_cname = exception_type_cname
self.exception_message = exception_message
def analyse_types(self, env):
pass
def may_be_none(self):
return False
def result_in_temp(self):
return self.arg.result_in_temp()
def calculate_result_code(self):
return self.arg.result()
def generate_result_code(self, code):
code.putln(
"if (unlikely(%s == Py_None)) {" % self.arg.result())
code.putln('PyErr_SetString(%s, "%s"); %s ' % (
self.exception_type_cname,
StringEncoding.escape_byte_string(
self.exception_message.encode('UTF-8')),
code.error_goto(self.pos)))
code.putln("}")
def generate_post_assignment_code(self, code):
self.arg.generate_post_assignment_code(code)
def free_temps(self, code):
self.arg.free_temps(code)
class CoerceToPyTypeNode(CoercionNode):
# This node is used to convert a C data type
# to a Python object.
type = py_object_type
is_temp = 1
def __init__(self, arg, env, type=py_object_type):
CoercionNode.__init__(self, arg)
if not arg.type.create_to_py_utility_code(env):
error(arg.pos,
"Cannot convert '%s' to Python object" % arg.type)
if type is not py_object_type:
self.type = py_object_type
elif arg.type.is_string:
self.type = bytes_type
elif arg.type is PyrexTypes.c_py_unicode_type:
self.type = unicode_type
gil_message = "Converting to Python object"
def may_be_none(self):
# FIXME: is this always safe?
return False
def coerce_to_boolean(self, env):
arg_type = self.arg.type
if (arg_type == PyrexTypes.c_bint_type or
(arg_type.is_pyobject and arg_type.name == 'bool')):
return self.arg.coerce_to_temp(env)
else:
return CoerceToBooleanNode(self, env)
def coerce_to_integer(self, env):
# If not already some C integer type, coerce to longint.
if self.arg.type.is_int:
return self.arg
else:
return self.arg.coerce_to(PyrexTypes.c_long_type, env)
def analyse_types(self, env):
# The arg is always already analysed
pass
def generate_result_code(self, code):
function = self.arg.type.to_py_function
code.putln('%s = %s(%s); %s' % (
self.result(),
function,
self.arg.result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
class CoerceIntToBytesNode(CoerceToPyTypeNode):
# This node is used to convert a C int type to a Python bytes
# object.
is_temp = 1
def __init__(self, arg, env):
arg = arg.coerce_to_simple(env)
CoercionNode.__init__(self, arg)
self.type = Builtin.bytes_type
def generate_result_code(self, code):
arg = self.arg
arg_result = arg.result()
if arg.type not in (PyrexTypes.c_char_type,
PyrexTypes.c_uchar_type,
PyrexTypes.c_schar_type):
if arg.type.signed:
code.putln("if ((%s < 0) || (%s > 255)) {" % (
arg_result, arg_result))
else:
code.putln("if (%s > 255) {" % arg_result)
code.putln('PyErr_Format(PyExc_OverflowError, '
'"value too large to pack into a byte"); %s' % (
code.error_goto(self.pos)))
code.putln('}')
temp = None
if arg.type is not PyrexTypes.c_char_type:
temp = code.funcstate.allocate_temp(PyrexTypes.c_char_type, manage_ref=False)
code.putln("%s = (char)%s;" % (temp, arg_result))
arg_result = temp
code.putln('%s = PyBytes_FromStringAndSize(&%s, 1); %s' % (
self.result(),
arg_result,
code.error_goto_if_null(self.result(), self.pos)))
if temp is not None:
code.funcstate.release_temp(temp)
code.put_gotref(self.py_result())
class CoerceFromPyTypeNode(CoercionNode):
# This node is used to convert a Python object
# to a C data type.
def __init__(self, result_type, arg, env):
CoercionNode.__init__(self, arg)
self.type = result_type
self.is_temp = 1
if not result_type.create_from_py_utility_code(env):
error(arg.pos,
"Cannot convert Python object to '%s'" % result_type)
if self.type.is_string and self.arg.is_ephemeral():
error(arg.pos,
"Obtaining char * from temporary Python value")
def analyse_types(self, env):
# The arg is always already analysed
pass
def generate_result_code(self, code):
function = self.type.from_py_function
operand = self.arg.py_result()
rhs = "%s(%s)" % (function, operand)
if self.type.is_enum:
rhs = typecast(self.type, c_long_type, rhs)
code.putln('%s = %s; %s' % (
self.result(),
rhs,
code.error_goto_if(self.type.error_condition(self.result()), self.pos)))
if self.type.is_pyobject:
code.put_gotref(self.py_result())
class CoerceToBooleanNode(CoercionNode):
# This node is used when a result needs to be used
# in a boolean context.
type = PyrexTypes.c_bint_type
_special_builtins = {
Builtin.list_type : 'PyList_GET_SIZE',
Builtin.tuple_type : 'PyTuple_GET_SIZE',
Builtin.bytes_type : 'PyBytes_GET_SIZE',
Builtin.unicode_type : 'PyUnicode_GET_SIZE',
}
def __init__(self, arg, env):
CoercionNode.__init__(self, arg)
if arg.type.is_pyobject:
self.is_temp = 1
def nogil_check(self, env):
if self.arg.type.is_pyobject and self._special_builtins.get(self.arg.type) is None:
self.gil_error()
gil_message = "Truth-testing Python object"
def check_const(self):
if self.is_temp:
self.not_const()
return False
return self.arg.check_const()
def calculate_result_code(self):
return "(%s != 0)" % self.arg.result()
def generate_result_code(self, code):
if not self.is_temp:
return
test_func = self._special_builtins.get(self.arg.type)
if test_func is not None:
code.putln("%s = (%s != Py_None) && (%s(%s) != 0);" % (
self.result(),
self.arg.py_result(),
test_func,
self.arg.py_result()))
else:
code.putln(
"%s = __Pyx_PyObject_IsTrue(%s); %s" % (
self.result(),
self.arg.py_result(),
code.error_goto_if_neg(self.result(), self.pos)))
class CoerceToComplexNode(CoercionNode):
def __init__(self, arg, dst_type, env):
if arg.type.is_complex:
arg = arg.coerce_to_simple(env)
self.type = dst_type
CoercionNode.__init__(self, arg)
dst_type.create_declaration_utility_code(env)
def calculate_result_code(self):
if self.arg.type.is_complex:
real_part = "__Pyx_CREAL(%s)" % self.arg.result()
imag_part = "__Pyx_CIMAG(%s)" % self.arg.result()
else:
real_part = self.arg.result()
imag_part = "0"
return "%s(%s, %s)" % (
self.type.from_parts,
real_part,
imag_part)
def generate_result_code(self, code):
pass
class CoerceToTempNode(CoercionNode):
# This node is used to force the result of another node
# to be stored in a temporary. It is only used if the
# argument node's result is not already in a temporary.
def __init__(self, arg, env):
CoercionNode.__init__(self, arg)
self.type = self.arg.type
self.constant_result = self.arg.constant_result
self.is_temp = 1
if self.type.is_pyobject:
self.result_ctype = py_object_type
gil_message = "Creating temporary Python reference"
def analyse_types(self, env):
# The arg is always already analysed
pass
def coerce_to_boolean(self, env):
self.arg = self.arg.coerce_to_boolean(env)
if self.arg.is_simple():
return self.arg
self.type = self.arg.type
self.result_ctype = self.type
return self
def generate_result_code(self, code):
#self.arg.generate_evaluation_code(code) # Already done
# by generic generate_subexpr_evaluation_code!
code.putln("%s = %s;" % (
self.result(), self.arg.result_as(self.ctype())))
if self.type.is_pyobject and self.use_managed_ref:
code.put_incref(self.result(), self.ctype())
class CloneNode(CoercionNode):
# This node is employed when the result of another node needs
# to be used multiple times. The argument node's result must
# be in a temporary. This node "borrows" the result from the
# argument node, and does not generate any evaluation or
# disposal code for it. The original owner of the argument
# node is responsible for doing those things.
subexprs = [] # Arg is not considered a subexpr
nogil_check = None
def __init__(self, arg):
CoercionNode.__init__(self, arg)
if hasattr(arg, 'type'):
self.type = arg.type
self.result_ctype = arg.result_ctype
if hasattr(arg, 'entry'):
self.entry = arg.entry
def result(self):
return self.arg.result()
def type_dependencies(self, env):
return self.arg.type_dependencies(env)
def infer_type(self, env):
return self.arg.infer_type(env)
def analyse_types(self, env):
self.type = self.arg.type
self.result_ctype = self.arg.result_ctype
self.is_temp = 1
if hasattr(self.arg, 'entry'):
self.entry = self.arg.entry
def generate_evaluation_code(self, code):
pass
def generate_result_code(self, code):
pass
def generate_disposal_code(self, code):
pass
def free_temps(self, code):
pass
class ModuleRefNode(ExprNode):
# Simple returns the module object
type = py_object_type
is_temp = False
subexprs = []
def analyse_types(self, env):
pass
def may_be_none(self):
return False
def calculate_result_code(self):
return Naming.module_cname
def generate_result_code(self, code):
pass
class DocstringRefNode(ExprNode):
# Extracts the docstring of the body element
subexprs = ['body']
type = py_object_type
is_temp = True
def __init__(self, pos, body):
ExprNode.__init__(self, pos)
assert body.type.is_pyobject
self.body = body
def analyse_types(self, env):
pass
def generate_result_code(self, code):
code.putln('%s = __Pyx_GetAttrString(%s, "__doc__"); %s' % (
self.result(), self.body.result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.result())
#------------------------------------------------------------------------------------
#
# Runtime support code
#
#------------------------------------------------------------------------------------
get_name_interned_utility_code = UtilityCode(
proto = """
static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name); /*proto*/
""",
impl = """
static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name) {
PyObject *result;
result = PyObject_GetAttr(dict, name);
if (!result)
PyErr_SetObject(PyExc_NameError, name);
return result;
}
""")
#------------------------------------------------------------------------------------
import_utility_code = UtilityCode(
proto = """
static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list); /*proto*/
""",
impl = """
static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list) {
PyObject *py_import = 0;
PyObject *empty_list = 0;
PyObject *module = 0;
PyObject *global_dict = 0;
PyObject *empty_dict = 0;
PyObject *list;
py_import = __Pyx_GetAttrString(%(BUILTINS)s, "__import__");
if (!py_import)
goto bad;
if (from_list)
list = from_list;
else {
empty_list = PyList_New(0);
if (!empty_list)
goto bad;
list = empty_list;
}
global_dict = PyModule_GetDict(%(GLOBALS)s);
if (!global_dict)
goto bad;
empty_dict = PyDict_New();
if (!empty_dict)
goto bad;
module = PyObject_CallFunctionObjArgs(py_import,
name, global_dict, empty_dict, list, NULL);
bad:
Py_XDECREF(empty_list);
Py_XDECREF(py_import);
Py_XDECREF(empty_dict);
return module;
}
""" % {
"BUILTINS": Naming.builtins_cname,
"GLOBALS": Naming.module_cname,
})
#------------------------------------------------------------------------------------
get_exception_utility_code = UtilityCode(
proto = """
static PyObject *__Pyx_GetExcValue(void); /*proto*/
""",
impl = """
static PyObject *__Pyx_GetExcValue(void) {
PyObject *type = 0, *value = 0, *tb = 0;
PyObject *tmp_type, *tmp_value, *tmp_tb;
PyObject *result = 0;
PyThreadState *tstate = PyThreadState_Get();
PyErr_Fetch(&type, &value, &tb);
PyErr_NormalizeException(&type, &value, &tb);
if (PyErr_Occurred())
goto bad;
if (!value) {
value = Py_None;
Py_INCREF(value);
}
tmp_type = tstate->exc_type;
tmp_value = tstate->exc_value;
tmp_tb = tstate->exc_traceback;
tstate->exc_type = type;
tstate->exc_value = value;
tstate->exc_traceback = tb;
/* Make sure tstate is in a consistent state when we XDECREF
these objects (XDECREF may run arbitrary code). */
Py_XDECREF(tmp_type);
Py_XDECREF(tmp_value);
Py_XDECREF(tmp_tb);
result = value;
Py_XINCREF(result);
type = 0;
value = 0;
tb = 0;
bad:
Py_XDECREF(type);
Py_XDECREF(value);
Py_XDECREF(tb);
return result;
}
""")
#------------------------------------------------------------------------------------
type_test_utility_code = UtilityCode(
proto = """
static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); /*proto*/
""",
impl = """
static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) {
if (unlikely(!type)) {
PyErr_Format(PyExc_SystemError, "Missing type object");
return 0;
}
if (likely(PyObject_TypeCheck(obj, type)))
return 1;
PyErr_Format(PyExc_TypeError, "Cannot convert %.200s to %.200s",
Py_TYPE(obj)->tp_name, type->tp_name);
return 0;
}
""")
#------------------------------------------------------------------------------------
create_class_utility_code = UtilityCode(
proto = """
static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name, const char *modname); /*proto*/
""",
impl = """
static PyObject *__Pyx_CreateClass(
PyObject *bases, PyObject *dict, PyObject *name, const char *modname)
{
PyObject *py_modname;
PyObject *result = 0;
#if PY_MAJOR_VERSION < 3
py_modname = PyString_FromString(modname);
#else
py_modname = PyUnicode_FromString(modname);
#endif
if (!py_modname)
goto bad;
if (PyDict_SetItemString(dict, "__module__", py_modname) < 0)
goto bad;
#if PY_MAJOR_VERSION < 3
result = PyClass_New(bases, dict, name);
#else
result = PyObject_CallFunctionObjArgs((PyObject *)&PyType_Type, name, bases, dict, NULL);
#endif
bad:
Py_XDECREF(py_modname);
return result;
}
""")
#------------------------------------------------------------------------------------
cpp_exception_utility_code = UtilityCode(
proto = """
#ifndef __Pyx_CppExn2PyErr
static void __Pyx_CppExn2PyErr() {
try {
if (PyErr_Occurred())
; // let the latest Python exn pass through and ignore the current one
else
throw;
} catch (const std::invalid_argument& exn) {
// Catch a handful of different errors here and turn them into the
// equivalent Python errors.
// Change invalid_argument to ValueError
PyErr_SetString(PyExc_ValueError, exn.what());
} catch (const std::out_of_range& exn) {
// Change out_of_range to IndexError
PyErr_SetString(PyExc_IndexError, exn.what());
} catch (const std::exception& exn) {
PyErr_SetString(PyExc_RuntimeError, exn.what());
}
catch (...)
{
PyErr_SetString(PyExc_RuntimeError, "Unknown exception");
}
}
#endif
""",
impl = ""
)
#------------------------------------------------------------------------------------
raise_noneattr_error_utility_code = UtilityCode(
proto = """
static CYTHON_INLINE void __Pyx_RaiseNoneAttributeError(const char* attrname);
""",
impl = '''
static CYTHON_INLINE void __Pyx_RaiseNoneAttributeError(const char* attrname) {
PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%s'", attrname);
}
''')
raise_noneindex_error_utility_code = UtilityCode(
proto = """
static CYTHON_INLINE void __Pyx_RaiseNoneIndexingError(void);
""",
impl = '''
static CYTHON_INLINE void __Pyx_RaiseNoneIndexingError(void) {
PyErr_SetString(PyExc_TypeError, "'NoneType' object is unsubscriptable");
}
''')
raise_none_iter_error_utility_code = UtilityCode(
proto = """
static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void);
""",
impl = '''
static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) {
PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable");
}
''')
#------------------------------------------------------------------------------------
getitem_dict_utility_code = UtilityCode(
proto = """
#if PY_MAJOR_VERSION >= 3
static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) {
PyObject *value;
if (unlikely(d == Py_None)) {
__Pyx_RaiseNoneIndexingError();
return NULL;
}
value = PyDict_GetItemWithError(d, key);
if (unlikely(!value)) {
if (!PyErr_Occurred())
PyErr_SetObject(PyExc_KeyError, key);
return NULL;
}
Py_INCREF(value);
return value;
}
#else
#define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key)
#endif
""",
requires = [raise_noneindex_error_utility_code])
#------------------------------------------------------------------------------------
getitem_int_pyunicode_utility_code = UtilityCode(
proto = '''
#define __Pyx_GetItemInt_Unicode(o, i, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \\
__Pyx_GetItemInt_Unicode_Fast(o, i) : \\
__Pyx_GetItemInt_Unicode_Generic(o, to_py_func(i)))
static CYTHON_INLINE Py_UNICODE __Pyx_GetItemInt_Unicode_Fast(PyObject* ustring, Py_ssize_t i) {
if (likely((0 <= i) & (i < PyUnicode_GET_SIZE(ustring)))) {
return PyUnicode_AS_UNICODE(ustring)[i];
} else if ((-PyUnicode_GET_SIZE(ustring) <= i) & (i < 0)) {
i += PyUnicode_GET_SIZE(ustring);
return PyUnicode_AS_UNICODE(ustring)[i];
} else {
PyErr_SetString(PyExc_IndexError, "string index out of range");
return (Py_UNICODE)-1;
}
}
static CYTHON_INLINE Py_UNICODE __Pyx_GetItemInt_Unicode_Generic(PyObject* ustring, PyObject* j) {
Py_UNICODE uchar;
PyObject *uchar_string;
if (!j) return (Py_UNICODE)-1;
uchar_string = PyObject_GetItem(ustring, j);
Py_DECREF(j);
if (!uchar_string) return (Py_UNICODE)-1;
uchar = PyUnicode_AS_UNICODE(uchar_string)[0];
Py_DECREF(uchar_string);
return uchar;
}
''')
getitem_int_utility_code = UtilityCode(
proto = """
static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) {
PyObject *r;
if (!j) return NULL;
r = PyObject_GetItem(o, j);
Py_DECREF(j);
return r;
}
""" + ''.join([
"""
#define __Pyx_GetItemInt_%(type)s(o, i, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \\
__Pyx_GetItemInt_%(type)s_Fast(o, i) : \\
__Pyx_GetItemInt_Generic(o, to_py_func(i)))
static CYTHON_INLINE PyObject *__Pyx_GetItemInt_%(type)s_Fast(PyObject *o, Py_ssize_t i) {
if (likely(o != Py_None)) {
if (likely((0 <= i) & (i < Py%(type)s_GET_SIZE(o)))) {
PyObject *r = Py%(type)s_GET_ITEM(o, i);
Py_INCREF(r);
return r;
}
else if ((-Py%(type)s_GET_SIZE(o) <= i) & (i < 0)) {
PyObject *r = Py%(type)s_GET_ITEM(o, Py%(type)s_GET_SIZE(o) + i);
Py_INCREF(r);
return r;
}
}
return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i));
}
""" % {'type' : type_name} for type_name in ('List', 'Tuple')
]) + """
#define __Pyx_GetItemInt(o, i, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \\
__Pyx_GetItemInt_Fast(o, i) : \\
__Pyx_GetItemInt_Generic(o, to_py_func(i)))
static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i) {
PyObject *r;
if (PyList_CheckExact(o) && ((0 <= i) & (i < PyList_GET_SIZE(o)))) {
r = PyList_GET_ITEM(o, i);
Py_INCREF(r);
}
else if (PyTuple_CheckExact(o) && ((0 <= i) & (i < PyTuple_GET_SIZE(o)))) {
r = PyTuple_GET_ITEM(o, i);
Py_INCREF(r);
}
else if (Py_TYPE(o)->tp_as_sequence && Py_TYPE(o)->tp_as_sequence->sq_item && (likely(i >= 0))) {
r = PySequence_GetItem(o, i);
}
else {
r = __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i));
}
return r;
}
""",
impl = """
""")
#------------------------------------------------------------------------------------
setitem_int_utility_code = UtilityCode(
proto = """
#define __Pyx_SetItemInt(o, i, v, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \\
__Pyx_SetItemInt_Fast(o, i, v) : \\
__Pyx_SetItemInt_Generic(o, to_py_func(i), v))
static CYTHON_INLINE int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v) {
int r;
if (!j) return -1;
r = PyObject_SetItem(o, j, v);
Py_DECREF(j);
return r;
}
static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObject *v) {
if (PyList_CheckExact(o) && ((0 <= i) & (i < PyList_GET_SIZE(o)))) {
Py_INCREF(v);
Py_DECREF(PyList_GET_ITEM(o, i));
PyList_SET_ITEM(o, i, v);
return 1;
}
else if (Py_TYPE(o)->tp_as_sequence && Py_TYPE(o)->tp_as_sequence->sq_ass_item && (likely(i >= 0)))
return PySequence_SetItem(o, i, v);
else {
PyObject *j = PyInt_FromSsize_t(i);
return __Pyx_SetItemInt_Generic(o, j, v);
}
}
""",
impl = """
""")
#------------------------------------------------------------------------------------
delitem_int_utility_code = UtilityCode(
proto = """
#define __Pyx_DelItemInt(o, i, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \\
__Pyx_DelItemInt_Fast(o, i) : \\
__Pyx_DelItem_Generic(o, to_py_func(i)))
static CYTHON_INLINE int __Pyx_DelItem_Generic(PyObject *o, PyObject *j) {
int r;
if (!j) return -1;
r = PyObject_DelItem(o, j);
Py_DECREF(j);
return r;
}
static CYTHON_INLINE int __Pyx_DelItemInt_Fast(PyObject *o, Py_ssize_t i) {
if (Py_TYPE(o)->tp_as_sequence && Py_TYPE(o)->tp_as_sequence->sq_ass_item && likely(i >= 0))
return PySequence_DelItem(o, i);
else {
PyObject *j = PyInt_FromSsize_t(i);
return __Pyx_DelItem_Generic(o, j);
}
}
""",
impl = """
""")
#------------------------------------------------------------------------------------
raise_too_many_values_to_unpack = UtilityCode(
proto = """
static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected);
""",
impl = '''
static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) {
PyErr_Format(PyExc_ValueError,
#if PY_VERSION_HEX < 0x02050000
"too many values to unpack (expected %d)", (int)expected);
#else
"too many values to unpack (expected %zd)", expected);
#endif
}
''')
raise_need_more_values_to_unpack = UtilityCode(
proto = """
static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index);
""",
impl = '''
static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) {
PyErr_Format(PyExc_ValueError,
#if PY_VERSION_HEX < 0x02050000
"need more than %d value%s to unpack", (int)index,
#else
"need more than %zd value%s to unpack", index,
#endif
(index == 1) ? "" : "s");
}
''')
#------------------------------------------------------------------------------------
tuple_unpacking_error_code = UtilityCode(
proto = """
static void __Pyx_UnpackTupleError(PyObject *, Py_ssize_t index); /*proto*/
""",
impl = """
static void __Pyx_UnpackTupleError(PyObject *t, Py_ssize_t index) {
if (t == Py_None) {
__Pyx_RaiseNoneNotIterableError();
} else if (PyTuple_GET_SIZE(t) < index) {
__Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(t));
} else {
__Pyx_RaiseTooManyValuesError(index);
}
}
""",
requires = [raise_none_iter_error_utility_code,
raise_need_more_values_to_unpack,
raise_too_many_values_to_unpack]
)
unpacking_utility_code = UtilityCode(
proto = """
static PyObject *__Pyx_UnpackItem(PyObject *, Py_ssize_t index); /*proto*/
static int __Pyx_EndUnpack(PyObject *, Py_ssize_t expected); /*proto*/
""",
impl = """
static PyObject *__Pyx_UnpackItem(PyObject *iter, Py_ssize_t index) {
PyObject *item;
if (!(item = PyIter_Next(iter))) {
if (!PyErr_Occurred()) {
__Pyx_RaiseNeedMoreValuesError(index);
}
}
return item;
}
static int __Pyx_EndUnpack(PyObject *iter, Py_ssize_t expected) {
PyObject *item;
if ((item = PyIter_Next(iter))) {
Py_DECREF(item);
__Pyx_RaiseTooManyValuesError(expected);
return -1;
}
else if (!PyErr_Occurred())
return 0;
else
return -1;
}
""",
requires = [raise_need_more_values_to_unpack,
raise_too_many_values_to_unpack]
)
#------------------------------------------------------------------------------------
# CPython supports calling functions with non-dict kwargs by
# converting them to a dict first
kwargs_call_utility_code = UtilityCode(
proto = """
static PyObject* __Pyx_PyEval_CallObjectWithKeywords(PyObject*, PyObject*, PyObject*); /*proto*/
""",
impl = """
static PyObject* __Pyx_PyEval_CallObjectWithKeywords(PyObject *callable, PyObject *args, PyObject *kwargs) {
PyObject* result;
if (likely(PyDict_Check(kwargs))) {
return PyEval_CallObjectWithKeywords(callable, args, kwargs);
} else {
PyObject* real_dict;
real_dict = PyObject_CallFunctionObjArgs((PyObject*)&PyDict_Type, kwargs, NULL);
if (unlikely(!real_dict))
return NULL;
result = PyEval_CallObjectWithKeywords(callable, args, real_dict);
Py_DECREF(real_dict);
return result; /* may be NULL */
}
}
""",
)
#------------------------------------------------------------------------------------
int_pow_utility_code = UtilityCode(
proto="""
static CYTHON_INLINE %(type)s %(func_name)s(%(type)s, %(type)s); /* proto */
""",
impl="""
static CYTHON_INLINE %(type)s %(func_name)s(%(type)s b, %(type)s e) {
%(type)s t = b;
switch (e) {
case 3:
t *= b;
case 2:
t *= b;
case 1:
return t;
case 0:
return 1;
}
if (unlikely(e<0)) return 0;
t = 1;
while (likely(e)) {
t *= (b * (e&1)) | ((~e)&1); /* 1 or b */
b *= b;
e >>= 1;
}
return t;
}
""")
# ------------------------------ Division ------------------------------------
div_int_utility_code = UtilityCode(
proto="""
static CYTHON_INLINE %(type)s __Pyx_div_%(type_name)s(%(type)s, %(type)s); /* proto */
""",
impl="""
static CYTHON_INLINE %(type)s __Pyx_div_%(type_name)s(%(type)s a, %(type)s b) {
%(type)s q = a / b;
%(type)s r = a - q*b;
q -= ((r != 0) & ((r ^ b) < 0));
return q;
}
""")
mod_int_utility_code = UtilityCode(
proto="""
static CYTHON_INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s, %(type)s); /* proto */
""",
impl="""
static CYTHON_INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s a, %(type)s b) {
%(type)s r = a %% b;
r += ((r != 0) & ((r ^ b) < 0)) * b;
return r;
}
""")
mod_float_utility_code = UtilityCode(
proto="""
static CYTHON_INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s, %(type)s); /* proto */
""",
impl="""
static CYTHON_INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s a, %(type)s b) {
%(type)s r = fmod%(math_h_modifier)s(a, b);
r += ((r != 0) & ((r < 0) ^ (b < 0))) * b;
return r;
}
""")
cdivision_warning_utility_code = UtilityCode(
proto="""
static int __Pyx_cdivision_warning(void); /* proto */
""",
impl="""
static int __Pyx_cdivision_warning(void) {
return PyErr_WarnExplicit(PyExc_RuntimeWarning,
"division with oppositely signed operands, C and Python semantics differ",
%(FILENAME)s,
%(LINENO)s,
__Pyx_MODULE_NAME,
NULL);
}
""" % {
'FILENAME': Naming.filename_cname,
'LINENO': Naming.lineno_cname,
})
# from intobject.c
division_overflow_test_code = UtilityCode(
proto="""
#define UNARY_NEG_WOULD_OVERFLOW(x) \
(((x) < 0) & ((unsigned long)(x) == 0-(unsigned long)(x)))
""")
binding_cfunc_utility_code = UtilityCode(
proto="""
#define %(binding_cfunc)s_USED 1
typedef struct {
PyCFunctionObject func;
} %(binding_cfunc)s_object;
PyTypeObject %(binding_cfunc)s_type;
PyTypeObject *%(binding_cfunc)s = NULL;
PyObject *%(binding_cfunc)s_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module); /* proto */
#define %(binding_cfunc)s_New(ml, self) %(binding_cfunc)s_NewEx(ml, self, NULL)
int %(binding_cfunc)s_init(void); /* proto */
""" % Naming.__dict__,
impl="""
PyObject *%(binding_cfunc)s_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module) {
%(binding_cfunc)s_object *op = PyObject_GC_New(%(binding_cfunc)s_object, %(binding_cfunc)s);
if (op == NULL)
return NULL;
op->func.m_ml = ml;
Py_XINCREF(self);
op->func.m_self = self;
Py_XINCREF(module);
op->func.m_module = module;
PyObject_GC_Track(op);
return (PyObject *)op;
}
static void %(binding_cfunc)s_dealloc(%(binding_cfunc)s_object *m) {
PyObject_GC_UnTrack(m);
Py_XDECREF(m->func.m_self);
Py_XDECREF(m->func.m_module);
PyObject_GC_Del(m);
}
static PyObject *%(binding_cfunc)s_descr_get(PyObject *func, PyObject *obj, PyObject *type) {
if (obj == Py_None)
obj = NULL;
return PyMethod_New(func, obj, type);
}
int %(binding_cfunc)s_init(void) {
%(binding_cfunc)s_type = PyCFunction_Type;
%(binding_cfunc)s_type.tp_name = __Pyx_NAMESTR("cython_binding_builtin_function_or_method");
%(binding_cfunc)s_type.tp_dealloc = (destructor)%(binding_cfunc)s_dealloc;
%(binding_cfunc)s_type.tp_descr_get = %(binding_cfunc)s_descr_get;
if (PyType_Ready(&%(binding_cfunc)s_type) < 0) {
return -1;
}
%(binding_cfunc)s = &%(binding_cfunc)s_type;
return 0;
}
""" % Naming.__dict__)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Future.py 0000664 0000000 0000000 00000000627 11446142532 0024613 0 ustar 00root root 0000000 0000000 def _get_feature(name):
import __future__
try:
return getattr(__future__, name)
except AttributeError:
# unique fake object for earlier Python versions
return object()
unicode_literals = _get_feature("unicode_literals")
with_statement = _get_feature("with_statement")
division = _get_feature("division")
print_function = _get_feature("print_function")
del _get_feature
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Interpreter.py 0000664 0000000 0000000 00000003251 11446142532 0025640 0 ustar 00root root 0000000 0000000 """
This module deals with interpreting the parse tree as Python
would have done, in the compiler.
For now this only covers parse tree to value conversion of
compile-time values.
"""
from Nodes import *
from ExprNodes import *
from Errors import CompileError
class EmptyScope(object):
def lookup(self, name):
return None
empty_scope = EmptyScope()
def interpret_compiletime_options(optlist, optdict, type_env=None, type_args=()):
"""
Tries to interpret a list of compile time option nodes.
The result will be a tuple (optlist, optdict) but where
all expression nodes have been interpreted. The result is
in the form of tuples (value, pos).
optlist is a list of nodes, while optdict is a DictNode (the
result optdict is a dict)
If type_env is set, all type nodes will be analysed and the resulting
type set. Otherwise only interpretateable ExprNodes
are allowed, other nodes raises errors.
A CompileError will be raised if there are problems.
"""
def interpret(node, ix):
if ix in type_args:
if type_env:
return (node.analyse_as_type(type_env), node.pos)
else:
raise CompileError(node.pos, "Type not allowed here.")
else:
return (node.compile_time_value(empty_scope), node.pos)
if optlist:
optlist = [interpret(x, ix) for ix, x in enumerate(optlist)]
if optdict:
assert isinstance(optdict, DictNode)
new_optdict = {}
for item in optdict.key_value_pairs:
new_optdict[item.key.value] = interpret(item.value, item.key.value)
optdict = new_optdict
return (optlist, new_optdict)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Lexicon.py 0000664 0000000 0000000 00000011566 11446142532 0024746 0 ustar 00root root 0000000 0000000 #
# Cython Scanner - Lexical Definitions
#
raw_prefixes = "rR"
string_prefixes = "cCuUbB"
IDENT = 'IDENT'
def make_lexicon():
from Cython.Plex import \
Str, Any, AnyBut, AnyChar, Rep, Rep1, Opt, Bol, Eol, Eof, \
TEXT, IGNORE, State, Lexicon
from Scanning import Method
letter = Any("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_")
digit = Any("0123456789")
bindigit = Any("01")
octdigit = Any("01234567")
hexdigit = Any("0123456789ABCDEFabcdef")
indentation = Bol + Rep(Any(" \t"))
decimal = Rep1(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") + Rep1(hexdigit)) |
(Any("Oo") + Rep1(octdigit)) |
(Any("Bb") + Rep1(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")
sq_string = (
Str("'") +
Rep(AnyBut("\\\n'") | (Str("\\") + AnyChar)) +
Str("'")
)
dq_string = (
Str('"') +
Rep(AnyBut('\\\n"') | (Str("\\") + AnyChar)) +
Str('"')
)
non_sq = AnyBut("'") | (Str('\\') + AnyChar)
tsq_string = (
Str("'''")
+ Rep(non_sq | (Str("'") + non_sq) | (Str("''") + non_sq))
+ Str("'''")
)
non_dq = AnyBut('"') | (Str('\\') + AnyChar)
tdq_string = (
Str('"""')
+ Rep(non_dq | (Str('"') + non_dq) | (Str('""') + non_dq))
+ Str('"""')
)
beginstring = Opt(Any(string_prefixes)) + Opt(Any(raw_prefixes)) + (Str("'") | Str('"') | Str("'''") | Str('"""'))
two_oct = octdigit + octdigit
three_oct = octdigit + octdigit + octdigit
two_hex = hexdigit + hexdigit
four_hex = two_hex + two_hex
escapeseq = Str("\\") + (two_oct | three_oct |
Str('u') + four_hex | Str('x') + two_hex |
Str('U') + four_hex + four_hex | AnyChar)
deco = Str("@")
bra = Any("([{")
ket = Any(")]}")
punct = Any(":,;+-*/|&<>=.%`~^?")
diphthong = Str("==", "<>", "!=", "<=", ">=", "<<", ">>", "**", "//",
"+=", "-=", "*=", "/=", "%=", "|=", "^=", "&=",
"<<=", ">>=", "**=", "//=", "->")
spaces = Rep1(Any(" \t\f"))
escaped_newline = Str("\\\n")
lineterm = Eol + Opt(Str("\n"))
comment = Str("#") + Rep(AnyBut("\n"))
return Lexicon([
(name, IDENT),
(intliteral, 'INT'),
(fltconst, 'FLOAT'),
(imagconst, 'IMAG'),
(deco, 'DECORATOR'),
(punct | diphthong, TEXT),
(bra, Method('open_bracket_action')),
(ket, Method('close_bracket_action')),
(lineterm, Method('newline_action')),
#(stringlit, 'STRING'),
(beginstring, Method('begin_string_action')),
(comment, IGNORE),
(spaces, IGNORE),
(escaped_newline, IGNORE),
State('INDENT', [
(comment + lineterm, Method('commentline')),
(Opt(spaces) + Opt(comment) + lineterm, IGNORE),
(indentation, Method('indentation_action')),
(Eof, Method('eof_action'))
]),
State('SQ_STRING', [
(escapeseq, 'ESCAPE'),
(Rep1(AnyBut("'\"\n\\")), 'CHARS'),
(Str('"'), 'CHARS'),
(Str("\n"), Method('unclosed_string_action')),
(Str("'"), Method('end_string_action')),
(Eof, 'EOF')
]),
State('DQ_STRING', [
(escapeseq, 'ESCAPE'),
(Rep1(AnyBut('"\n\\')), 'CHARS'),
(Str("'"), 'CHARS'),
(Str("\n"), Method('unclosed_string_action')),
(Str('"'), Method('end_string_action')),
(Eof, 'EOF')
]),
State('TSQ_STRING', [
(escapeseq, 'ESCAPE'),
(Rep1(AnyBut("'\"\n\\")), 'CHARS'),
(Any("'\""), 'CHARS'),
(Str("\n"), 'NEWLINE'),
(Str("'''"), Method('end_string_action')),
(Eof, 'EOF')
]),
State('TDQ_STRING', [
(escapeseq, 'ESCAPE'),
(Rep1(AnyBut('"\'\n\\')), 'CHARS'),
(Any("'\""), 'CHARS'),
(Str("\n"), 'NEWLINE'),
(Str('"""'), Method('end_string_action')),
(Eof, 'EOF')
]),
(Eof, Method('eof_action'))
],
# FIXME: Plex 1.9 needs different args here from Plex 1.1.4
#debug_flags = scanner_debug_flags,
#debug_file = scanner_dump_file
)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Main.py 0000664 0000000 0000000 00000076564 11446142532 0024242 0 ustar 00root root 0000000 0000000 #
# Cython Top Level
#
import os, sys, re
if sys.version_info[:2] < (2, 3):
sys.stderr.write("Sorry, Cython requires Python 2.3 or later\n")
sys.exit(1)
try:
set
except NameError:
# Python 2.3
from sets import Set as set
import itertools
from time import time
import Code
import Errors
import Parsing
import Version
from Scanning import PyrexScanner, FileSourceDescriptor
from Errors import PyrexError, CompileError, InternalError, error, warning
from Symtab import BuiltinScope, ModuleScope
from Cython import Utils
from Cython.Utils import open_new_file, replace_suffix
import CythonScope
import DebugFlags
module_name_pattern = re.compile(r"[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)*$")
verbose = 0
def dumptree(t):
# For quick debugging in pipelines
print t.dump()
return t
def abort_on_errors(node):
# Stop the pipeline if there are any errors.
if Errors.num_errors != 0:
raise InternalError, "abort"
return node
class CompilationData(object):
# Bundles the information that is passed from transform to transform.
# (For now, this is only)
# While Context contains every pxd ever loaded, path information etc.,
# this only contains the data related to a single compilation pass
#
# pyx ModuleNode Main code tree of this compilation.
# pxds {string : ModuleNode} Trees for the pxds used in the pyx.
# codewriter CCodeWriter Where to output final code.
# options CompilationOptions
# result CompilationResult
pass
class Context(object):
# This class encapsulates the context needed for compiling
# one or more Cython implementation files along with their
# associated and imported declaration files. It includes
# the root of the module import namespace and the list
# of directories to search for include files.
#
# modules {string : ModuleScope}
# include_directories [string]
# future_directives [object]
# language_level int currently 2 or 3 for Python 2/3
def __init__(self, include_directories, compiler_directives, cpp=False, language_level=2):
#self.modules = {"__builtin__" : BuiltinScope()}
import Builtin, CythonScope
self.modules = {"__builtin__" : Builtin.builtin_scope}
self.modules["cython"] = CythonScope.create_cython_scope(self)
self.include_directories = include_directories
self.future_directives = set()
self.compiler_directives = compiler_directives
self.cpp = cpp
self.pxds = {} # full name -> node tree
standard_include_path = os.path.abspath(os.path.normpath(
os.path.join(os.path.dirname(__file__), os.path.pardir, 'Includes')))
self.include_directories = include_directories + [standard_include_path]
self.set_language_level(language_level)
def set_language_level(self, level):
self.language_level = level
if level >= 3:
from Future import print_function, unicode_literals
self.future_directives.add(print_function)
self.future_directives.add(unicode_literals)
def create_pipeline(self, pxd, py=False):
from Visitor import PrintTree
from ParseTreeTransforms import WithTransform, NormalizeTree, PostParse, PxdPostParse
from ParseTreeTransforms import AnalyseDeclarationsTransform, AnalyseExpressionsTransform
from ParseTreeTransforms import CreateClosureClasses, MarkClosureVisitor, DecoratorTransform
from ParseTreeTransforms import InterpretCompilerDirectives, TransformBuiltinMethods
from TypeInference import MarkAssignments, MarkOverflowingArithmetic
from ParseTreeTransforms import AlignFunctionDefinitions, GilCheck
from AnalysedTreeTransforms import AutoTestDictTransform
from AutoDocTransforms import EmbedSignature
from Optimize import FlattenInListTransform, SwitchTransform, IterationTransform
from Optimize import EarlyReplaceBuiltinCalls, OptimizeBuiltinCalls
from Optimize import ConstantFolding, FinalOptimizePhase
from Optimize import DropRefcountingTransform
from Buffer import IntroduceBufferAuxiliaryVars
from ModuleNode import check_c_declarations, check_c_declarations_pxd
if pxd:
_check_c_declarations = check_c_declarations_pxd
_specific_post_parse = PxdPostParse(self)
else:
_check_c_declarations = check_c_declarations
_specific_post_parse = None
if py and not pxd:
_align_function_definitions = AlignFunctionDefinitions(self)
else:
_align_function_definitions = None
return [
NormalizeTree(self),
PostParse(self),
_specific_post_parse,
InterpretCompilerDirectives(self, self.compiler_directives),
_align_function_definitions,
MarkClosureVisitor(self),
ConstantFolding(),
FlattenInListTransform(),
WithTransform(self),
DecoratorTransform(self),
AnalyseDeclarationsTransform(self),
CreateClosureClasses(self),
AutoTestDictTransform(self),
EmbedSignature(self),
EarlyReplaceBuiltinCalls(self), ## Necessary?
MarkAssignments(self),
MarkOverflowingArithmetic(self),
TransformBuiltinMethods(self), ## Necessary?
IntroduceBufferAuxiliaryVars(self),
_check_c_declarations,
AnalyseExpressionsTransform(self),
OptimizeBuiltinCalls(self), ## Necessary?
IterationTransform(),
SwitchTransform(),
DropRefcountingTransform(),
FinalOptimizePhase(self),
GilCheck(),
]
def create_pyx_pipeline(self, options, result, py=False):
def generate_pyx_code(module_node):
module_node.process_implementation(options, result)
result.compilation_source = module_node.compilation_source
return result
def inject_pxd_code(module_node):
from textwrap import dedent
stats = module_node.body.stats
for name, (statlistnode, scope) in self.pxds.iteritems():
# Copy over function nodes to the module
# (this seems strange -- I believe the right concept is to split
# ModuleNode into a ModuleNode and a CodeGenerator, and tell that
# CodeGenerator to generate code both from the pyx and pxd ModuleNodes.
stats.append(statlistnode)
# Until utility code is moved to code generation phase everywhere,
# we need to copy it over to the main scope
module_node.scope.utility_code_list.extend(scope.utility_code_list)
return module_node
test_support = []
if options.evaluate_tree_assertions:
from Cython.TestUtils import TreeAssertVisitor
test_support.append(TreeAssertVisitor())
if options.debug:
import ParseTreeTransforms
debug_transform = [ParseTreeTransforms.DebuggerTransform(self)]
else:
debug_transform = []
return list(itertools.chain(
[create_parse(self)],
self.create_pipeline(pxd=False, py=py),
test_support,
[inject_pxd_code, abort_on_errors],
debug_transform,
[generate_pyx_code]))
def create_pxd_pipeline(self, scope, module_name):
def parse_pxd(source_desc):
tree = self.parse(source_desc, scope, pxd=True,
full_module_name=module_name)
tree.scope = scope
tree.is_pxd = True
return tree
from CodeGeneration import ExtractPxdCode
# The pxd pipeline ends up with a CCodeWriter containing the
# code of the pxd, as well as a pxd scope.
return [parse_pxd] + self.create_pipeline(pxd=True) + [
ExtractPxdCode(self),
]
def create_py_pipeline(self, options, result):
return self.create_pyx_pipeline(options, result, py=True)
def process_pxd(self, source_desc, scope, module_name):
pipeline = self.create_pxd_pipeline(scope, module_name)
result = self.run_pipeline(pipeline, source_desc)
return result
def nonfatal_error(self, exc):
return Errors.report_error(exc)
def run_pipeline(self, pipeline, source):
error = None
data = source
try:
for phase in pipeline:
if phase is not None:
if DebugFlags.debug_verbose_pipeline:
t = time()
print "Entering pipeline phase %r" % phase
data = phase(data)
if DebugFlags.debug_verbose_pipeline:
print " %.3f seconds" % (time() - t)
except CompileError, err:
# err is set
Errors.report_error(err)
error = err
except InternalError, err:
# Only raise if there was not an earlier error
if Errors.num_errors == 0:
raise
error = err
return (error, data)
def find_module(self, module_name,
relative_to = None, pos = None, need_pxd = 1):
# 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
# the corresponding .pxd file and process it.
# If relative_to is not None, it must be a module scope,
# and the module will first be searched for relative to
# that module, provided its name is not a dotted name.
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))
scope = None
pxd_pathname = None
if not module_name_pattern.match(module_name):
if pos is None:
pos = (module_name, 0, 0)
raise CompileError(pos,
"'%s' is not a valid module name" % module_name)
if "." not in module_name and relative_to:
if debug_find_module:
print("...trying relative import")
scope = relative_to.lookup_submodule(module_name)
if not scope:
qualified_name = relative_to.qualify_name(module_name)
pxd_pathname = self.find_pxd_file(qualified_name, pos)
if pxd_pathname:
scope = relative_to.find_submodule(module_name)
if not scope:
if debug_find_module:
print("...trying absolute import")
scope = self
for name in module_name.split("."):
scope = scope.find_submodule(name)
if debug_find_module:
print("...scope =", scope)
if not scope.pxd_file_loaded:
if debug_find_module:
print("...pxd not loaded")
scope.pxd_file_loaded = 1
if not pxd_pathname:
if debug_find_module:
print("...looking for pxd file")
pxd_pathname = self.find_pxd_file(module_name, pos)
if debug_find_module:
print("......found ", pxd_pathname)
if not pxd_pathname and need_pxd:
package_pathname = self.search_include_directories(module_name, ".py", pos)
if package_pathname and package_pathname.endswith('__init__.py'):
pass
else:
error(pos, "'%s.pxd' not found" % module_name)
if pxd_pathname:
try:
if debug_find_module:
print("Context.find_module: Parsing %s" % pxd_pathname)
source_desc = FileSourceDescriptor(pxd_pathname)
err, result = self.process_pxd(source_desc, scope, module_name)
if err:
raise err
(pxd_codenodes, pxd_scope) = result
self.pxds[module_name] = (pxd_codenodes, pxd_scope)
except CompileError:
pass
return scope
def find_pxd_file(self, qualified_name, pos):
# Search include path 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)
if pxd is None: # XXX Keep this until Includes/Deprecated is removed
if (qualified_name.startswith('python') or
qualified_name in ('stdlib', 'stdio', 'stl')):
standard_include_path = os.path.abspath(os.path.normpath(
os.path.join(os.path.dirname(__file__), os.path.pardir, 'Includes')))
deprecated_include_path = os.path.join(standard_include_path, 'Deprecated')
self.include_directories.append(deprecated_include_path)
try:
pxd = self.search_include_directories(qualified_name, ".pxd", pos)
finally:
self.include_directories.pop()
if pxd:
name = qualified_name
if name.startswith('python'):
warning(pos, "'%s' is deprecated, use 'cpython'" % name, 1)
elif name in ('stdlib', 'stdio'):
warning(pos, "'%s' is deprecated, use 'libc.%s'" % (name, name), 1)
elif name in ('stl'):
warning(pos, "'%s' is deprecated, use 'libcpp.*.*'" % name, 1)
return pxd
def find_pyx_file(self, qualified_name, pos):
# Search include path for the .pyx file corresponding to the
# given fully-qualified module name, as for find_pxd_file().
return self.search_include_directories(qualified_name, ".pyx", pos)
def find_include_file(self, filename, pos):
# Search list of include directories for filename.
# Reports an error and returns None if not found.
path = self.search_include_directories(filename, "", pos,
include=True)
if not path:
error(pos, "'%s' not found" % filename)
return path
def search_include_directories(self, 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.
dirs = self.include_directories
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 = [self.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 = names[:-1]
module_name = names[-1]
module_filename = module_name + suffix
package_filename = "__init__" + suffix
for dir in dirs:
path = os.path.join(dir, dotted_filename)
if Utils.path_exists(path):
return path
if not include:
package_dir = self.check_package_dir(dir, package_names)
if package_dir is not None:
path = os.path.join(package_dir, module_filename)
if Utils.path_exists(path):
return path
path = os.path.join(dir, package_dir, module_name,
package_filename)
if Utils.path_exists(path):
return path
return None
def find_root_package_dir(self, file_path):
dir = os.path.dirname(file_path)
while self.is_package_dir(dir):
parent = os.path.dirname(dir)
if parent == dir:
break
dir = parent
return dir
def check_package_dir(self, dir, package_names):
for dirname in package_names:
dir = os.path.join(dir, dirname)
if not self.is_package_dir(dir):
return None
return dir
def c_file_out_of_date(self, source_path):
c_path = Utils.replace_suffix(source_path, ".c")
if not os.path.exists(c_path):
return 1
c_time = Utils.modification_time(c_path)
if Utils.file_newer_than(source_path, c_time):
return 1
pos = [source_path]
pxd_path = Utils.replace_suffix(source_path, ".pxd")
if os.path.exists(pxd_path) and Utils.file_newer_than(pxd_path, c_time):
return 1
for kind, name in self.read_dependency_file(source_path):
if kind == "cimport":
dep_path = self.find_pxd_file(name, pos)
elif kind == "include":
dep_path = self.search_include_directories(name, pos)
else:
continue
if dep_path and Utils.file_newer_than(dep_path, c_time):
return 1
return 0
def find_cimported_module_names(self, source_path):
return [ name for kind, name in self.read_dependency_file(source_path)
if kind == "cimport" ]
def is_package_dir(self, dir_path):
# Return true if the given directory is a package directory.
for filename in ("__init__.py",
"__init__.pyx",
"__init__.pxd"):
path = os.path.join(dir_path, filename)
if Utils.path_exists(path):
return 1
def read_dependency_file(self, source_path):
dep_path = Utils.replace_suffix(source_path, ".dep")
if os.path.exists(dep_path):
f = open(dep_path, "rU")
chunks = [ line.strip().split(" ", 1)
for line in f.readlines()
if " " in line.strip() ]
f.close()
return chunks
else:
return ()
def lookup_submodule(self, name):
# Look up a top-level module. Returns None if not found.
return self.modules.get(name, None)
def find_submodule(self, name):
# Find a top-level module, creating a new one if needed.
scope = self.lookup_submodule(name)
if not scope:
scope = ModuleScope(name,
parent_module = None, context = self)
self.modules[name] = scope
return scope
def parse(self, source_desc, scope, pxd, full_module_name):
if not isinstance(source_desc, FileSourceDescriptor):
raise RuntimeError("Only file sources for code supported")
source_filename = source_desc.filename
scope.cpp = self.cpp
# Parse the given source file and return a parse tree.
try:
f = Utils.open_source_file(source_filename, "rU")
try:
s = PyrexScanner(f, source_desc, source_encoding = f.encoding,
scope = scope, context = self)
tree = Parsing.p_module(s, pxd, full_module_name)
finally:
f.close()
except UnicodeDecodeError, msg:
#import traceback
#traceback.print_exc()
error((source_desc, 0, 0), "Decoding error, missing or incorrect coding= at top of source (%s)" % msg)
if Errors.num_errors > 0:
raise CompileError
return tree
def extract_module_name(self, path, options):
# Find fully_qualified module name from the full pathname
# of a source file.
dir, filename = os.path.split(path)
module_name, _ = os.path.splitext(filename)
if "." in module_name:
return module_name
if module_name == "__init__":
dir, module_name = os.path.split(dir)
names = [module_name]
while self.is_package_dir(dir):
parent, package_name = os.path.split(dir)
if parent == dir:
break
names.append(package_name)
dir = parent
names.reverse()
return ".".join(names)
def setup_errors(self, options, result):
if options.use_listing_file:
result.listing_file = Utils.replace_suffix(source, ".lis")
path = result.listing_file
else:
path = None
Errors.open_listing_file(path=path,
echo_to_stderr=options.errors_to_stderr)
def teardown_errors(self, err, options, result):
source_desc = result.compilation_source.source_desc
if not isinstance(source_desc, FileSourceDescriptor):
raise RuntimeError("Only file sources for code supported")
Errors.close_listing_file()
result.num_errors = Errors.num_errors
if result.num_errors > 0:
err = True
if err and result.c_file:
try:
Utils.castrate_file(result.c_file, os.stat(source_desc.filename))
except EnvironmentError:
pass
result.c_file = None
def create_parse(context):
def parse(compsrc):
source_desc = compsrc.source_desc
full_module_name = compsrc.full_module_name
initial_pos = (source_desc, 1, 0)
scope = context.find_module(full_module_name, pos = initial_pos, need_pxd = 0)
tree = context.parse(source_desc, scope, pxd = 0, full_module_name = full_module_name)
tree.compilation_source = compsrc
tree.scope = scope
tree.is_pxd = False
return tree
return parse
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
if options.output_file:
result.c_file = os.path.join(compilation_source.cwd, options.output_file)
else:
if options.cplus:
c_suffix = ".cpp"
else:
c_suffix = ".c"
result.c_file = Utils.replace_suffix(source_desc.filename, c_suffix)
return result
def run_pipeline(source, options, full_module_name = None):
# Set up context
context = Context(options.include_path, options.compiler_directives,
options.cplus, options.language_level)
# Set up source object
cwd = os.getcwd()
source_desc = FileSourceDescriptor(os.path.join(cwd, source))
full_module_name = full_module_name or context.extract_module_name(source, options)
source = CompilationSource(source_desc, full_module_name, cwd)
# Set up result object
result = create_default_resultobj(source, options)
# Get pipeline
if source_desc.filename.endswith(".py"):
pipeline = context.create_py_pipeline(options, result)
else:
pipeline = context.create_pyx_pipeline(options, result)
context.setup_errors(options, result)
err, enddata = context.run_pipeline(pipeline, source)
context.teardown_errors(err, options, result)
return result
#------------------------------------------------------------------------
#
# Main Python entry points
#
#------------------------------------------------------------------------
class CompilationSource(object):
"""
Contains the data necesarry to start up a compilation pipeline for
a single compilation unit.
"""
def __init__(self, source_desc, full_module_name, cwd):
self.source_desc = source_desc
self.full_module_name = full_module_name
self.cwd = cwd
class CompilationOptions(object):
"""
Options to the Cython compiler:
show_version boolean Display version number
use_listing_file boolean Generate a .lis file
errors_to_stderr boolean Echo errors to stderr when using .lis
include_path [string] Directories to search for include files
output_file string Name of generated .c file
generate_pxi boolean Generate .pxi file for public declarations
recursive boolean Recursively find and compile dependencies
timestamps boolean Only compile changed source files. If None,
defaults to true when recursive is true.
verbose boolean Always print source names being compiled
quiet boolean Don't print source names in recursive mode
compiler_directives dict Overrides for pragma options (see Options.py)
evaluate_tree_assertions boolean Test support: evaluate parse tree assertions
language_level integer The Python language level: 2 or 3
cplus boolean Compile as c++ code
"""
def __init__(self, defaults = None, **kw):
self.include_path = []
if defaults:
if isinstance(defaults, CompilationOptions):
defaults = defaults.__dict__
else:
defaults = default_options
self.__dict__.update(defaults)
self.__dict__.update(kw)
class CompilationResult(object):
"""
Results from the Cython compiler:
c_file string or None The generated C source file
h_file string or None The generated C header file
i_file string or None The generated .pxi file
api_file string or None The generated C API .h file
listing_file string or None File of error messages
object_file string or None Result of compiling the C file
extension_file string or None Result of linking the object file
num_errors integer Number of compilation errors
compilation_source CompilationSource
"""
def __init__(self):
self.c_file = None
self.h_file = None
self.i_file = None
self.api_file = None
self.listing_file = None
self.object_file = None
self.extension_file = None
self.main_source_file = None
class CompilationResultSet(dict):
"""
Results from compiling multiple Pyrex source files. A mapping
from source file paths to CompilationResult instances. Also
has the following attributes:
num_errors integer Total number of compilation errors
"""
num_errors = 0
def add(self, source, result):
self[source] = result
self.num_errors += result.num_errors
def compile_single(source, options, full_module_name = None):
"""
compile_single(source, options, full_module_name)
Compile the given Pyrex implementation file and return a CompilationResult.
Always compiles a single file; does not perform timestamp checking or
recursion.
"""
return run_pipeline(source, options, full_module_name)
def compile_multiple(sources, options):
"""
compile_multiple(sources, options)
Compiles the given sequence of Pyrex implementation files and returns
a CompilationResultSet. Performs timestamp checking and/or recursion
if these are specified in the options.
"""
sources = [os.path.abspath(source) for source in sources]
processed = set()
results = CompilationResultSet()
recursive = options.recursive
timestamps = options.timestamps
if timestamps is None:
timestamps = recursive
verbose = options.verbose or ((recursive or timestamps) and not options.quiet)
for source in sources:
if source not in processed:
# Compiling multiple sources in one context doesn't quite
# work properly yet.
if not timestamps or context.c_file_out_of_date(source):
if verbose:
sys.stderr.write("Compiling %s\n" % source)
result = run_pipeline(source, options)
results.add(source, result)
processed.add(source)
if recursive:
for module_name in context.find_cimported_module_names(source):
path = context.find_pyx_file(module_name, [source])
if path:
sources.append(path)
else:
sys.stderr.write(
"Cannot find .pyx file for cimported module '%s'\n" % module_name)
return results
def compile(source, options = None, full_module_name = None, **kwds):
"""
compile(source [, options], [, = ]...)
Compile one or more Pyrex implementation files, with optional timestamp
checking and recursing on dependecies. The source argument may be a string
or a sequence of strings If it is a string and no recursion or timestamp
checking is requested, a CompilationResult is returned, otherwise a
CompilationResultSet is returned.
"""
options = CompilationOptions(defaults = options, **kwds)
if isinstance(source, basestring) and not options.timestamps \
and not options.recursive:
return compile_single(source, options, full_module_name)
else:
return compile_multiple(source, options)
#------------------------------------------------------------------------
#
# Main command-line entry point
#
#------------------------------------------------------------------------
def setuptools_main():
return main(command_line = 1)
def main(command_line = 0):
args = sys.argv[1:]
any_failures = 0
if command_line:
from CmdLine import parse_command_line
options, sources = parse_command_line(args)
else:
options = CompilationOptions(default_options)
sources = args
if options.show_version:
sys.stderr.write("Cython version %s\n" % Version.version)
if options.working_path!="":
os.chdir(options.working_path)
try:
result = compile(sources, options)
if result.num_errors > 0:
any_failures = 1
except (EnvironmentError, PyrexError), e:
sys.stderr.write(str(e) + '\n')
any_failures = 1
if any_failures:
sys.exit(1)
#------------------------------------------------------------------------
#
# Set the default options depending on the platform
#
#------------------------------------------------------------------------
default_options = dict(
show_version = 0,
use_listing_file = 0,
errors_to_stderr = 1,
cplus = 0,
output_file = None,
annotate = False,
generate_pxi = 0,
working_path = "",
recursive = 0,
timestamps = None,
verbose = 0,
quiet = 0,
compiler_directives = {},
evaluate_tree_assertions = False,
emit_linenums = False,
language_level = 2,
debug = False,
)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/ModuleNode.py 0000664 0000000 0000000 00000317677 11446142532 0025414 0 ustar 00root root 0000000 0000000 #
# Pyrex - Module parse tree node
#
import os, time
from PyrexTypes import CPtrType
import Future
try:
set
except NameError: # Python 2.3
from sets import Set as set
import Annotate
import Code
import Naming
import Nodes
import Options
import PyrexTypes
import TypeSlots
import Version
import DebugFlags
from Errors import error, warning
from PyrexTypes import py_object_type
from Cython.Utils import open_new_file, replace_suffix
from Code import UtilityCode
from StringEncoding import escape_byte_string, EncodedString
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
class ModuleNode(Nodes.Node, Nodes.BlockNode):
# doc string or None
# body StatListNode
#
# referenced_modules [ModuleScope]
# full_module_name string
#
# scope The module scope.
# compilation_source A CompilationSource (see Main)
# directives Top-level compiler directives
child_attrs = ["body"]
directives = None
def analyse_declarations(self, env):
if Options.embed_pos_in_docstring:
env.doc = EncodedString(u'File: %s (starting at line %s)' % Nodes.relative_position(self.pos))
if not self.doc is None:
env.doc = EncodedString(env.doc + u'\n' + self.doc)
env.doc.encoding = self.doc.encoding
else:
env.doc = self.doc
env.directives = self.directives
self.body.analyse_declarations(env)
def process_implementation(self, options, result):
env = self.scope
env.return_type = PyrexTypes.c_void_type
self.referenced_modules = []
self.find_referenced_modules(env, self.referenced_modules, {})
if options.recursive:
self.generate_dep_file(env, result)
self.generate_c_code(env, options, result)
self.generate_h_code(env, options, result)
self.generate_api_code(env, result)
def has_imported_c_functions(self):
for module in self.referenced_modules:
for entry in module.cfunc_entries:
if entry.defined_in_pxd:
return 1
return 0
def generate_dep_file(self, env, result):
modules = self.referenced_modules
if len(modules) > 1 or env.included_files:
dep_file = replace_suffix(result.c_file, ".dep")
f = open(dep_file, "w")
try:
for module in modules:
if module is not env:
f.write("cimport %s\n" % module.qualified_name)
for path in module.included_files:
f.write("include %s\n" % path)
finally:
f.close()
def generate_h_code(self, env, options, result):
def h_entries(entries, pxd = 0):
return [entry for entry in entries
if entry.visibility == 'public' or pxd and entry.defined_in_pxd]
h_types = h_entries(env.type_entries)
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:
result.h_file = replace_suffix(result.c_file, ".h")
h_code = Code.CCodeWriter()
Code.GlobalState(h_code)
if options.generate_pxi:
result.i_file = replace_suffix(result.c_file, ".pxi")
i_code = Code.PyrexCodeWriter(result.i_file)
else:
i_code = None
guard = Naming.h_guard_prefix + env.qualified_name.replace(".", "__")
h_code.put_h_guard(guard)
self.generate_extern_c_macro_definition(h_code)
self.generate_type_header_code(h_types, h_code)
h_code.putln("")
h_code.putln("#ifndef %s" % Naming.api_guard_prefix + self.api_name(env))
if h_vars:
h_code.putln("")
for entry in h_vars:
self.generate_public_declaration(entry, h_code, i_code)
if h_funcs:
h_code.putln("")
for entry in h_funcs:
self.generate_public_declaration(entry, h_code, i_code)
if h_extension_types:
h_code.putln("")
for entry in h_extension_types:
self.generate_cclass_header_code(entry.type, h_code)
if i_code:
self.generate_cclass_include_code(entry.type, i_code)
h_code.putln("")
h_code.putln("#endif")
h_code.putln("")
h_code.putln("PyMODINIT_FUNC init%s(void);" % env.module_name)
h_code.putln("")
h_code.putln("#endif")
h_code.copyto(open_new_file(result.h_file))
def generate_public_declaration(self, entry, h_code, i_code):
h_code.putln("%s %s;" % (
Naming.extern_c_macro,
entry.type.declaration_code(
entry.cname, dll_linkage = "DL_IMPORT")))
if i_code:
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, result):
api_funcs = []
public_extension_types = []
has_api_extension_types = 0
for entry in env.cfunc_entries:
if entry.api:
api_funcs.append(entry)
for entry in env.c_class_entries:
if entry.visibility == 'public':
public_extension_types.append(entry)
if entry.api:
has_api_extension_types = 1
if api_funcs or has_api_extension_types:
result.api_file = replace_suffix(result.c_file, "_api.h")
h_code = Code.CCodeWriter()
Code.GlobalState(h_code)
name = self.api_name(env)
guard = Naming.api_guard_prefix + name
h_code.put_h_guard(guard)
h_code.putln('#include "Python.h"')
if result.h_file:
h_code.putln('#include "%s"' % os.path.basename(result.h_file))
for entry in public_extension_types:
type = entry.type
h_code.putln("")
h_code.putln("static PyTypeObject *%s;" % type.typeptr_cname)
h_code.putln("#define %s (*%s)" % (
type.typeobj_cname, type.typeptr_cname))
if api_funcs:
h_code.putln("")
for entry in api_funcs:
type = CPtrType(entry.type)
h_code.putln("static %s;" % type.declaration_code(entry.cname))
h_code.putln("")
h_code.put_h_guard(Naming.api_func_guard + "import_module")
h_code.put(import_module_utility_code.impl)
h_code.putln("")
h_code.putln("#endif")
if api_funcs:
h_code.putln("")
h_code.put(function_import_utility_code.impl)
if public_extension_types:
h_code.putln("")
h_code.put(type_import_utility_code.impl)
h_code.putln("")
h_code.putln("static int import_%s(void) {" % name)
h_code.putln("PyObject *module = 0;")
h_code.putln('module = __Pyx_ImportModule("%s");' % env.qualified_name)
h_code.putln("if (!module) goto bad;")
for entry in api_funcs:
sig = entry.type.signature_string()
h_code.putln(
'if (__Pyx_ImportFunction(module, "%s", (void (**)(void))&%s, "%s") < 0) goto bad;' % (
entry.name,
entry.cname,
sig))
h_code.putln("Py_DECREF(module); module = 0;")
for entry in public_extension_types:
self.generate_type_import_call(
entry.type, h_code,
"if (!%s) goto bad;" % entry.type.typeptr_cname)
h_code.putln("return 0;")
h_code.putln("bad:")
h_code.putln("Py_XDECREF(module);")
h_code.putln("return -1;")
h_code.putln("}")
h_code.putln("")
h_code.putln("#endif")
h_code.copyto(open_new_file(result.api_file))
def generate_cclass_header_code(self, type, h_code):
h_code.putln("%s DL_IMPORT(PyTypeObject) %s;" % (
Naming.extern_c_macro,
type.typeobj_cname))
def generate_cclass_include_code(self, type, i_code):
i_code.putln("cdef extern class %s.%s:" % (
type.module_name, type.name))
i_code.indent()
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))
else:
i_code.putln("pass")
i_code.dedent()
def generate_c_code(self, env, options, result):
modules = self.referenced_modules
if Options.annotate or options.annotate:
emit_linenums = False
rootwriter = Annotate.AnnotationCCodeWriter()
else:
emit_linenums = options.emit_linenums
rootwriter = Code.CCodeWriter(emit_linenums=emit_linenums)
globalstate = Code.GlobalState(rootwriter, emit_linenums)
globalstate.initialize_main_c_code()
h_code = globalstate['h_code']
self.generate_module_preamble(env, modules, h_code)
globalstate.module_pos = self.pos
globalstate.directives = self.directives
globalstate.use_utility_code(refnanny_utility_code)
code = globalstate['before_global_var']
code.putln('#define __Pyx_MODULE_NAME "%s"' % self.full_module_name)
code.putln("int %s%s = 0;" % (Naming.module_is_main, self.full_module_name.replace('.', '__')))
code.putln("")
code.putln("/* Implementation of %s */" % env.qualified_name)
code = globalstate['all_the_rest']
self.generate_cached_builtins_decls(env, code)
# generate lambda function definitions
for node in env.lambda_defs:
node.generate_function_definitions(env, code)
# generate normal function definitions
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, code)
# init_globals is inserted before this
self.generate_module_init_func(modules[:-1], env, globalstate['init_module'])
self.generate_module_cleanup_func(env, globalstate['cleanup_module'])
if Options.embed:
self.generate_main_method(env, globalstate['main_method'])
self.generate_filename_table(globalstate['filename_table'])
self.generate_declarations_for_modules(env, modules, globalstate)
h_code.write('\n')
for utilcode in env.utility_code_list:
globalstate.use_utility_code(utilcode)
globalstate.finalize_main_c_code()
f = open_new_file(result.c_file)
rootwriter.copyto(f)
f.close()
result.c_file_generated = 1
if Options.annotate or options.annotate:
self.annotate(rootwriter)
rootwriter.save_annotation(result.main_source_file, result.c_file)
def find_referenced_modules(self, env, module_list, modules_seen):
if env not in modules_seen:
modules_seen[env] = 1
for imported_module in env.cimported_modules:
self.find_referenced_modules(imported_module, module_list, modules_seen)
module_list.append(env)
def sort_types_by_inheritance(self, type_dict, getkey):
# copy the types into a list moving each parent type before
# its first child
type_items = type_dict.items()
type_list = []
for i, item in enumerate(type_items):
key, new_entry = item
# collect all base classes to check for children
hierarchy = set()
base = new_entry
while base:
base_type = base.type.base_type
if not base_type:
break
base_key = getkey(base_type)
hierarchy.add(base_key)
base = type_dict.get(base_key)
new_entry.base_keys = hierarchy
# find the first (sub-)subclass and insert before that
for j in range(i):
entry = type_list[j]
if key in entry.base_keys:
type_list.insert(j, new_entry)
break
else:
type_list.append(new_entry)
return type_list
def sort_type_hierarchy(self, module_list, env):
vtab_dict = {}
vtabslot_dict = {}
for module in module_list:
for entry in module.c_class_entries:
if not entry.in_cinclude:
type = entry.type
if type.vtabstruct_cname:
vtab_dict[type.vtabstruct_cname] = entry
all_defined_here = module is env
for entry in module.type_entries:
if all_defined_here or entry.defined_in_pxd:
type = entry.type
if type.is_extension_type and not entry.in_cinclude:
type = entry.type
vtabslot_dict[type.objstruct_cname] = entry
def vtabstruct_cname(entry_type):
return entry_type.vtabstruct_cname
vtab_list = self.sort_types_by_inheritance(
vtab_dict, vtabstruct_cname)
def objstruct_cname(entry_type):
return entry_type.objstruct_cname
vtabslot_list = self.sort_types_by_inheritance(
vtabslot_dict, objstruct_cname)
return (vtab_list, vtabslot_list)
def generate_type_definitions(self, env, modules, vtab_list, vtabslot_list, code):
vtabslot_entries = set(vtabslot_list)
for module in modules:
definition = module is env
if definition:
type_entries = module.type_entries
else:
type_entries = []
for entry in module.type_entries:
if entry.defined_in_pxd:
type_entries.append(entry)
for entry in type_entries:
if not entry.in_cinclude:
#print "generate_type_header_code:", entry.name, repr(entry.type) ###
type = entry.type
if type.is_typedef: # Must test this first!
self.generate_typedef(entry, code)
elif type.is_struct_or_union:
self.generate_struct_union_definition(entry, code)
elif type.is_enum:
self.generate_enum_definition(entry, code)
elif type.is_extension_type and entry not in vtabslot_entries:
self.generate_objstruct_definition(type, code)
for entry in vtabslot_list:
self.generate_objstruct_definition(entry.type, code)
for entry in vtab_list:
self.generate_typeobject_predeclaration(entry, code)
self.generate_exttype_vtable_struct(entry, code)
self.generate_exttype_vtabptr_declaration(entry, code)
def generate_declarations_for_modules(self, env, modules, globalstate):
typecode = globalstate['type_declarations']
typecode.putln("")
typecode.putln("/* Type declarations */")
vtab_list, vtabslot_list = self.sort_type_hierarchy(modules, env)
self.generate_type_definitions(
env, modules, vtab_list, vtabslot_list, typecode)
modulecode = globalstate['module_declarations']
for module in modules:
defined_here = module is env
modulecode.putln("/* Module declarations from %s */" %
module.qualified_name)
self.generate_global_declarations(module, modulecode, defined_here)
self.generate_cfunction_predeclarations(module, modulecode, defined_here)
def generate_module_preamble(self, env, cimported_modules, code):
code.putln("/* Generated by Cython %s on %s */" % (
Version.version, time.asctime()))
code.putln("")
code.putln("#define PY_SSIZE_T_CLEAN")
for filename in env.python_include_files:
code.putln('#include "%s"' % filename)
code.putln("#ifndef Py_PYTHON_H")
code.putln(" #error Python headers needed to compile C extensions, please install development version of Python.")
code.putln("#else")
code.globalstate["end"].putln("#endif /* Py_PYTHON_H */")
code.put("""
#include /* For offsetof */
#ifndef offsetof
#define offsetof(type, member) ( (size_t) & ((type*)0) -> member )
#endif
#if !defined(WIN32) && !defined(MS_WINDOWS)
#ifndef __stdcall
#define __stdcall
#endif
#ifndef __cdecl
#define __cdecl
#endif
#ifndef __fastcall
#define __fastcall
#endif
#endif
#ifndef DL_IMPORT
#define DL_IMPORT(t) t
#endif
#ifndef DL_EXPORT
#define DL_EXPORT(t) t
#endif
#ifndef PY_LONG_LONG
#define PY_LONG_LONG LONG_LONG
#endif
#if PY_VERSION_HEX < 0x02040000
#define METH_COEXIST 0
#define PyDict_CheckExact(op) (Py_TYPE(op) == &PyDict_Type)
#define PyDict_Contains(d,o) PySequence_Contains(d,o)
#endif
#if PY_VERSION_HEX < 0x02050000
typedef int Py_ssize_t;
#define PY_SSIZE_T_MAX INT_MAX
#define PY_SSIZE_T_MIN INT_MIN
#define PY_FORMAT_SIZE_T \"\"
#define PyInt_FromSsize_t(z) PyInt_FromLong(z)
#define PyInt_AsSsize_t(o) PyInt_AsLong(o)
#define PyNumber_Index(o) PyNumber_Int(o)
#define PyIndex_Check(o) PyNumber_Check(o)
#define PyErr_WarnEx(category, message, stacklevel) PyErr_Warn(category, message)
#endif
#if PY_VERSION_HEX < 0x02060000
#define Py_REFCNT(ob) (((PyObject*)(ob))->ob_refcnt)
#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
#define Py_SIZE(ob) (((PyVarObject*)(ob))->ob_size)
#define PyVarObject_HEAD_INIT(type, size) \\
PyObject_HEAD_INIT(type) size,
#define PyType_Modified(t)
typedef struct {
void *buf;
PyObject *obj;
Py_ssize_t len;
Py_ssize_t itemsize;
int readonly;
int ndim;
char *format;
Py_ssize_t *shape;
Py_ssize_t *strides;
Py_ssize_t *suboffsets;
void *internal;
} Py_buffer;
#define PyBUF_SIMPLE 0
#define PyBUF_WRITABLE 0x0001
#define PyBUF_FORMAT 0x0004
#define PyBUF_ND 0x0008
#define PyBUF_STRIDES (0x0010 | PyBUF_ND)
#define PyBUF_C_CONTIGUOUS (0x0020 | PyBUF_STRIDES)
#define PyBUF_F_CONTIGUOUS (0x0040 | PyBUF_STRIDES)
#define PyBUF_ANY_CONTIGUOUS (0x0080 | PyBUF_STRIDES)
#define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES)
#endif
#if PY_MAJOR_VERSION < 3
#define __Pyx_BUILTIN_MODULE_NAME "__builtin__"
#else
#define __Pyx_BUILTIN_MODULE_NAME "builtins"
#endif
#if PY_MAJOR_VERSION >= 3
#define Py_TPFLAGS_CHECKTYPES 0
#define Py_TPFLAGS_HAVE_INDEX 0
#endif
#if (PY_VERSION_HEX < 0x02060000) || (PY_MAJOR_VERSION >= 3)
#define Py_TPFLAGS_HAVE_NEWBUFFER 0
#endif
#if PY_MAJOR_VERSION >= 3
#define PyBaseString_Type PyUnicode_Type
#define PyStringObject PyUnicodeObject
#define PyString_Type PyUnicode_Type
#define PyString_Check PyUnicode_Check
#define PyString_CheckExact PyUnicode_CheckExact
#endif
#if PY_VERSION_HEX < 0x02060000
#define PyBytesObject PyStringObject
#define PyBytes_Type PyString_Type
#define PyBytes_Check PyString_Check
#define PyBytes_CheckExact PyString_CheckExact
#define PyBytes_FromString PyString_FromString
#define PyBytes_FromStringAndSize PyString_FromStringAndSize
#define PyBytes_FromFormat PyString_FromFormat
#define PyBytes_DecodeEscape PyString_DecodeEscape
#define PyBytes_AsString PyString_AsString
#define PyBytes_AsStringAndSize PyString_AsStringAndSize
#define PyBytes_Size PyString_Size
#define PyBytes_AS_STRING PyString_AS_STRING
#define PyBytes_GET_SIZE PyString_GET_SIZE
#define PyBytes_Repr PyString_Repr
#define PyBytes_Concat PyString_Concat
#define PyBytes_ConcatAndDel PyString_ConcatAndDel
#define PySet_Check(obj) PyObject_TypeCheck(obj, &PySet_Type)
#define PyFrozenSet_Check(obj) PyObject_TypeCheck(obj, &PyFrozenSet_Type)
#endif
#ifndef PySet_CheckExact
# define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type)
#endif
#if PY_MAJOR_VERSION >= 3
#define PyInt_Type PyLong_Type
#define PyInt_Check(op) PyLong_Check(op)
#define PyInt_CheckExact(op) PyLong_CheckExact(op)
#define PyInt_FromString PyLong_FromString
#define PyInt_FromUnicode PyLong_FromUnicode
#define PyInt_FromLong PyLong_FromLong
#define PyInt_FromSize_t PyLong_FromSize_t
#define PyInt_FromSsize_t PyLong_FromSsize_t
#define PyInt_AsLong PyLong_AsLong
#define PyInt_AS_LONG PyLong_AS_LONG
#define PyInt_AsSsize_t PyLong_AsSsize_t
#define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask
#define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask
#endif
#if PY_MAJOR_VERSION >= 3
#define PyBoolObject PyLongObject
#endif
""")
code.put("""
#if PY_MAJOR_VERSION >= 3
#define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y)
#define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y)
#else
""")
if Future.division in env.context.future_directives:
code.putln(" #define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y)")
code.putln(" #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y)")
else:
code.putln(" #define __Pyx_PyNumber_Divide(x,y) PyNumber_Divide(x,y)")
code.putln(" #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceDivide(x,y)")
code.putln("#endif")
code.put("""
#if PY_MAJOR_VERSION >= 3
#define PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : PyInstanceMethod_New(func))
#endif
#if PY_VERSION_HEX < 0x02050000
#define __Pyx_GetAttrString(o,n) PyObject_GetAttrString((o),((char *)(n)))
#define __Pyx_SetAttrString(o,n,a) PyObject_SetAttrString((o),((char *)(n)),(a))
#define __Pyx_DelAttrString(o,n) PyObject_DelAttrString((o),((char *)(n)))
#else
#define __Pyx_GetAttrString(o,n) PyObject_GetAttrString((o),(n))
#define __Pyx_SetAttrString(o,n,a) PyObject_SetAttrString((o),(n),(a))
#define __Pyx_DelAttrString(o,n) PyObject_DelAttrString((o),(n))
#endif
#if PY_VERSION_HEX < 0x02050000
#define __Pyx_NAMESTR(n) ((char *)(n))
#define __Pyx_DOCSTR(n) ((char *)(n))
#else
#define __Pyx_NAMESTR(n) (n)
#define __Pyx_DOCSTR(n) (n)
#endif
""")
code.putln("")
self.generate_extern_c_macro_definition(code)
code.putln("")
code.putln("#if defined(WIN32) || defined(MS_WINDOWS)")
code.putln("#define _USE_MATH_DEFINES")
code.putln("#endif")
code.putln("#include ")
code.putln("#define %s" % Naming.api_guard_prefix + self.api_name(env))
self.generate_includes(env, cimported_modules, code)
if env.directives['ccomplex']:
code.putln("")
code.putln("#if !defined(CYTHON_CCOMPLEX)")
code.putln("#define CYTHON_CCOMPLEX 1")
code.putln("#endif")
code.putln("")
code.put(Nodes.utility_function_predeclarations)
code.put(PyrexTypes.type_conversion_predeclarations)
code.put(Nodes.branch_prediction_macros)
code.putln('')
code.putln('static PyObject *%s;' % env.module_cname)
code.putln('static PyObject *%s;' % Naming.builtins_cname)
code.putln('static PyObject *%s;' % Naming.empty_tuple)
code.putln('static PyObject *%s;' % Naming.empty_bytes)
if Options.pre_import is not None:
code.putln('static PyObject *%s;' % Naming.preimport_cname)
code.putln('static int %s;' % Naming.lineno_cname)
code.putln('static int %s = 0;' % Naming.clineno_cname)
code.putln('static const char * %s= %s;' % (Naming.cfilenm_cname, Naming.file_c_macro))
code.putln('static const char *%s;' % Naming.filename_cname)
# XXX this is a mess
for utility_code in PyrexTypes.c_int_from_py_function.specialize_list:
env.use_utility_code(utility_code)
for utility_code in PyrexTypes.c_long_from_py_function.specialize_list:
env.use_utility_code(utility_code)
def generate_extern_c_macro_definition(self, code):
name = Naming.extern_c_macro
code.putln("#ifdef __cplusplus")
code.putln('#define %s extern "C"' % name)
code.putln("#else")
code.putln("#define %s extern" % name)
code.putln("#endif")
def generate_includes(self, env, cimported_modules, code):
includes = []
for filename in env.include_files:
byte_decoded_filenname = str(filename)
if byte_decoded_filenname[0] == '<' and byte_decoded_filenname[-1] == '>':
code.putln('#include %s' % byte_decoded_filenname)
else:
code.putln('#include "%s"' % byte_decoded_filenname)
def generate_filename_table(self, code):
code.putln("")
code.putln("static const char *%s[] = {" % Naming.filetable_cname)
if code.globalstate.filename_list:
for source_desc in code.globalstate.filename_list:
filename = os.path.basename(source_desc.get_filenametable_entry())
escaped_filename = filename.replace("\\", "\\\\").replace('"', r'\"')
code.putln('"%s",' % escaped_filename)
else:
# Some C compilers don't like an empty array
code.putln("0")
code.putln("};")
def generate_type_predeclarations(self, env, code):
pass
def generate_type_header_code(self, type_entries, code):
# Generate definitions of structs/unions/enums/typedefs/objstructs.
#self.generate_gcc33_hack(env, code) # Is this still needed?
#for entry in env.type_entries:
for entry in type_entries:
if not entry.in_cinclude:
#print "generate_type_header_code:", entry.name, repr(entry.type) ###
type = entry.type
if type.is_typedef: # Must test this first!
self.generate_typedef(entry, code)
elif type.is_struct_or_union:
self.generate_struct_union_definition(entry, code)
elif type.is_enum:
self.generate_enum_definition(entry, code)
elif type.is_extension_type:
self.generate_objstruct_definition(type, code)
def generate_gcc33_hack(self, env, code):
# Workaround for spurious warning generation in gcc 3.3
code.putln("")
for entry in env.c_class_entries:
type = entry.type
if not type.typedef_flag:
name = type.objstruct_cname
if name.startswith("__pyx_"):
tail = name[6:]
else:
tail = name
code.putln("typedef struct %s __pyx_gcc33_%s;" % (
name, tail))
def generate_typedef(self, entry, code):
base_type = entry.type.typedef_base_type
if base_type.is_numeric:
writer = code.globalstate['numeric_typedefs']
else:
writer = code
writer.putln("")
writer.putln("typedef %s;" % base_type.declaration_code(entry.cname))
def sue_header_footer(self, type, kind, name):
if type.typedef_flag:
header = "typedef %s {" % kind
footer = "} %s;" % name
else:
header = "%s %s {" % (kind, name)
footer = "};"
return header, footer
def generate_struct_union_definition(self, entry, code):
code.mark_pos(entry.pos)
type = entry.type
scope = type.scope
if scope:
kind = type.kind
packed = type.is_struct and type.packed
if packed:
kind = "%s %s" % (type.kind, "__Pyx_PACKED")
code.globalstate.use_utility_code(packed_struct_utility_code)
header, footer = \
self.sue_header_footer(type, kind, type.cname)
code.putln("")
if packed:
code.putln("#if defined(__SUNPRO_C)")
code.putln(" #pragma pack(1)")
code.putln("#elif !defined(__GNUC__)")
code.putln(" #pragma pack(push, 1)")
code.putln("#endif")
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")
for attr in var_entries:
code.putln(
"%s;" %
attr.type.declaration_code(attr.cname))
code.putln(footer)
if packed:
code.putln("#if defined(__SUNPRO_C)")
code.putln(" #pragma pack()")
code.putln("#elif !defined(__GNUC__)")
code.putln(" #pragma pack(pop)")
code.putln("#endif")
def generate_enum_definition(self, entry, code):
code.mark_pos(entry.pos)
type = entry.type
name = entry.cname or entry.name or ""
header, footer = \
self.sue_header_footer(type, "enum", name)
code.putln("")
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")
else:
last_entry = enum_values[-1]
# this does not really generate code, just builds the result value
for value_entry in enum_values:
if value_entry.value_node is not None:
value_entry.value_node.generate_evaluation_code(code)
for value_entry in enum_values:
if value_entry.value_node is None:
value_code = value_entry.cname
else:
value_code = ("%s = %s" % (
value_entry.cname,
value_entry.value_node.result()))
if value_entry is not last_entry:
value_code += ","
code.putln(value_code)
code.putln(footer)
def generate_typeobject_predeclaration(self, entry, code):
code.putln("")
name = entry.type.typeobj_cname
if name:
if entry.visibility == 'extern' and not entry.in_cinclude:
code.putln("%s DL_IMPORT(PyTypeObject) %s;" % (
Naming.extern_c_macro,
name))
elif entry.visibility == 'public':
#code.putln("DL_EXPORT(PyTypeObject) %s;" % name)
code.putln("%s DL_EXPORT(PyTypeObject) %s;" % (
Naming.extern_c_macro,
name))
# ??? Do we really need the rest of this? ???
#else:
# code.putln("staticforward PyTypeObject %s;" % name)
def generate_exttype_vtable_struct(self, entry, code):
code.mark_pos(entry.pos)
# Generate struct declaration for an extension type's vtable.
type = entry.type
scope = type.scope
if type.vtabstruct_cname:
code.putln("")
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.name))
code.putln(
"};")
def generate_exttype_vtabptr_declaration(self, entry, code):
code.mark_pos(entry.pos)
# Generate declaration of pointer to an extension type's vtable.
type = entry.type
if type.vtabptr_cname:
code.putln("static struct %s *%s;" % (
type.vtabstruct_cname,
type.vtabptr_cname))
def generate_objstruct_definition(self, type, code):
code.mark_pos(type.pos)
# Generate object struct definition for an
# extension type.
if not type.scope:
return # Forward declared but never defined
header, footer = \
self.sue_header_footer(type, "struct", type.objstruct_cname)
code.putln("")
code.putln(header)
base_type = type.base_type
if base_type:
code.putln(
"%s%s %s;" % (
("struct ", "")[base_type.typedef_flag],
base_type.objstruct_cname,
Naming.obj_base_cname))
else:
code.putln(
"PyObject_HEAD")
if type.vtabslot_cname and not (type.base_type and type.base_type.vtabslot_cname):
code.putln(
"struct %s *%s;" % (
type.vtabstruct_cname,
type.vtabslot_cname))
for attr in type.scope.var_entries:
code.putln(
"%s;" %
attr.type.declaration_code(attr.cname))
code.putln(footer)
if type.objtypedef_cname is not None:
# Only for exposing public typedef name.
code.putln("typedef struct %s %s;" % (type.objstruct_cname, type.objtypedef_cname))
def generate_global_declarations(self, env, code, definition):
code.putln("")
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.put_var_declarations(env.var_entries, static = 1,
dll_linkage = "DL_EXPORT", definition = definition)
def generate_cfunction_predeclarations(self, env, code, definition):
for entry in env.cfunc_entries:
if entry.inline_func_in_pxd or (not entry.in_cinclude and (definition
or entry.defined_in_pxd or entry.visibility == 'extern')):
if entry.visibility in ('public', 'extern'):
dll_linkage = "DL_EXPORT"
else:
dll_linkage = None
type = entry.type
if not definition and entry.defined_in_pxd:
type = CPtrType(type)
header = type.declaration_code(entry.cname,
dll_linkage = dll_linkage)
if entry.visibility == 'private':
storage_class = "static "
elif entry.visibility == 'public':
storage_class = ""
else:
storage_class = "%s " % Naming.extern_c_macro
if entry.func_modifiers:
modifiers = '%s ' % ' '.join([
modifier.upper() for modifier in entry.func_modifiers])
else:
modifiers = ''
code.putln("%s%s%s; /*proto*/" % (
storage_class,
modifiers,
header))
def generate_typeobj_definitions(self, env, code):
full_module_name = env.qualified_name
for entry in env.c_class_entries:
#print "generate_typeobj_definitions:", entry.name
#print "...visibility =", entry.visibility
if entry.visibility != 'extern':
type = entry.type
scope = type.scope
if scope: # could be None if there was an error
self.generate_exttype_vtable(scope, code)
self.generate_new_function(scope, code)
self.generate_dealloc_function(scope, code)
if scope.needs_gc():
self.generate_traverse_function(scope, code)
self.generate_clear_function(scope, code)
if scope.defines_any(["__getitem__"]):
self.generate_getitem_int_function(scope, code)
if scope.defines_any(["__setitem__", "__delitem__"]):
self.generate_ass_subscript_function(scope, code)
if scope.defines_any(["__getslice__", "__setslice__", "__delslice__"]):
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")
if scope.defines_any(["__setslice__", "__delslice__"]):
self.generate_ass_slice_function(scope, code)
if scope.defines_any(["__getattr__","__getattribute__"]):
self.generate_getattro_function(scope, code)
if scope.defines_any(["__setattr__", "__delattr__"]):
self.generate_setattro_function(scope, code)
if scope.defines_any(["__get__"]):
self.generate_descr_get_function(scope, code)
if scope.defines_any(["__set__", "__delete__"]):
self.generate_descr_set_function(scope, code)
self.generate_property_accessors(scope, code)
self.generate_method_table(scope, code)
self.generate_getset_table(scope, code)
self.generate_typeobj_definition(full_module_name, entry, code)
def generate_exttype_vtable(self, scope, code):
# Generate the definition of an extension type's vtable.
type = scope.parent_type
if type.vtable_cname:
code.putln("static struct %s %s;" % (
type.vtabstruct_cname,
type.vtable_cname))
def generate_self_cast(self, scope, code):
type = scope.parent_type
code.putln(
"%s = (%s)o;" % (
type.declaration_code("p"),
type.declaration_code("")))
def generate_new_function(self, scope, code):
tp_slot = TypeSlots.ConstructorSlot("tp_new", '__new__')
slot_func = scope.mangle_internal("tp_new")
type = scope.parent_type
base_type = type.base_type
py_attrs = []
for entry in scope.var_entries:
if entry.type.is_pyobject:
py_attrs.append(entry)
need_self_cast = type.vtabslot_cname or py_attrs
code.putln("")
code.putln(
"static PyObject *%s(PyTypeObject *t, PyObject *a, PyObject *k) {"
% scope.mangle_internal("tp_new"))
if need_self_cast:
code.putln(
"%s;"
% scope.parent_type.declaration_code("p"))
if base_type:
tp_new = TypeSlots.get_base_slot_function(scope, tp_slot)
if tp_new is None:
tp_new = "%s->tp_new" % base_type.typeptr_cname
code.putln(
"PyObject *o = %s(t, a, k);" % tp_new)
else:
code.putln(
"PyObject *o = (*t->tp_alloc)(t, 0);")
code.putln(
"if (!o) return 0;")
if need_self_cast:
code.putln(
"p = %s;"
% type.cast_code("o"))
#if need_self_cast:
# self.generate_self_cast(scope, code)
if type.vtabslot_cname:
vtab_base_type = type
while vtab_base_type.base_type and vtab_base_type.base_type.vtabstruct_cname:
vtab_base_type = vtab_base_type.base_type
if vtab_base_type is not type:
struct_type_cast = "(struct %s*)" % vtab_base_type.vtabstruct_cname
else:
struct_type_cast = ""
code.putln("p->%s = %s%s;" % (
type.vtabslot_cname,
struct_type_cast, type.vtabptr_cname))
for entry in py_attrs:
if scope.is_internal or entry.name == "__weakref__":
# internal classes do not need None inits
code.putln("p->%s = 0;" % entry.cname)
else:
code.put_init_var_to_py_none(entry, "p->%s", nanny=False)
entry = scope.lookup_here("__new__")
if entry and entry.is_special:
if entry.trivial_signature:
cinit_args = "o, %s, NULL" % Naming.empty_tuple
else:
cinit_args = "o, a, k"
code.putln(
"if (%s(%s) < 0) {" %
(entry.func_cname, cinit_args))
code.put_decref_clear("o", py_object_type, nanny=False);
code.putln(
"}")
code.putln(
"return o;")
code.putln(
"}")
def generate_dealloc_function(self, scope, code):
tp_slot = TypeSlots.ConstructorSlot("tp_dealloc", '__dealloc__')
slot_func = scope.mangle_internal("tp_dealloc")
base_type = scope.parent_type.base_type
if tp_slot.slot_code(scope) != slot_func:
return # never used
code.putln("")
code.putln(
"static void %s(PyObject *o) {"
% scope.mangle_internal("tp_dealloc"))
py_attrs = []
weakref_slot = scope.lookup_here("__weakref__")
for entry in scope.var_entries:
if entry.type.is_pyobject and entry is not weakref_slot:
py_attrs.append(entry)
if py_attrs or weakref_slot in scope.var_entries:
self.generate_self_cast(scope, code)
self.generate_usr_dealloc_call(scope, code)
if weakref_slot in scope.var_entries:
code.putln("if (p->__weakref__) PyObject_ClearWeakRefs(o);")
for entry in py_attrs:
code.put_xdecref("p->%s" % entry.cname, entry.type, nanny=False)
if base_type:
tp_dealloc = TypeSlots.get_base_slot_function(scope, tp_slot)
if tp_dealloc is None:
tp_dealloc = "%s->tp_dealloc" % base_type.typeptr_cname
code.putln(
"%s(o);" % tp_dealloc)
else:
code.putln(
"(*Py_TYPE(o)->tp_free)(o);")
code.putln(
"}")
def generate_usr_dealloc_call(self, scope, code):
entry = scope.lookup_here("__dealloc__")
if entry:
code.putln(
"{")
code.putln(
"PyObject *etype, *eval, *etb;")
code.putln(
"PyErr_Fetch(&etype, &eval, &etb);")
code.putln(
"++Py_REFCNT(o);")
code.putln(
"%s(o);" %
entry.func_cname)
code.putln(
"if (PyErr_Occurred()) PyErr_WriteUnraisable(o);")
code.putln(
"--Py_REFCNT(o);")
code.putln(
"PyErr_Restore(etype, eval, etb);")
code.putln(
"}")
def generate_traverse_function(self, scope, code):
tp_slot = TypeSlots.GCDependentSlot("tp_traverse")
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
code.putln("")
code.putln(
"static int %s(PyObject *o, visitproc v, void *a) {"
% slot_func)
py_attrs = []
for entry in scope.var_entries:
if entry.type.is_pyobject and entry.name != "__weakref__":
py_attrs.append(entry)
if base_type or py_attrs:
code.putln("int e;")
if py_attrs:
self.generate_self_cast(scope, code)
if base_type:
# want to call it explicitly if possible so inlining can be performed
static_call = TypeSlots.get_base_slot_function(scope, tp_slot)
if static_call:
code.putln("e = %s(o, v, a); if (e) return e;" % static_call)
else:
code.putln("if (%s->tp_traverse) {" % base_type.typeptr_cname)
code.putln(
"e = %s->tp_traverse(o, v, a); if (e) return e;" %
base_type.typeptr_cname)
code.putln("}")
for entry in py_attrs:
var_code = "p->%s" % entry.cname
code.putln(
"if (%s) {"
% var_code)
if entry.type.is_extension_type:
var_code = "((PyObject*)%s)" % var_code
code.putln(
"e = (*v)(%s, a); if (e) return e;"
% var_code)
code.putln(
"}")
code.putln(
"return 0;")
code.putln(
"}")
def generate_clear_function(self, scope, code):
tp_slot = TypeSlots.GCDependentSlot("tp_clear")
slot_func = scope.mangle_internal("tp_clear")
base_type = scope.parent_type.base_type
if tp_slot.slot_code(scope) != slot_func:
return # never used
code.putln("")
code.putln("static int %s(PyObject *o) {" % slot_func)
py_attrs = []
for entry in scope.var_entries:
if entry.type.is_pyobject and entry.name != "__weakref__":
py_attrs.append(entry)
if py_attrs:
self.generate_self_cast(scope, code)
code.putln("PyObject* tmp;")
if base_type:
# want to call it explicitly if possible so inlining can be performed
static_call = TypeSlots.get_base_slot_function(scope, tp_slot)
if static_call:
code.putln("%s(o);" % static_call)
else:
code.putln("if (%s->tp_clear) {" % base_type.typeptr_cname)
code.putln("%s->tp_clear(o);" % base_type.typeptr_cname)
code.putln("}")
for entry in py_attrs:
name = "p->%s" % entry.cname
code.putln("tmp = ((PyObject*)%s);" % name)
code.put_init_to_py_none(name, entry.type, nanny=False)
code.putln("Py_XDECREF(tmp);")
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"))
code.putln(
"PyObject *r;")
code.putln(
"PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0;")
code.putln(
"r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x);")
code.putln(
"Py_DECREF(x);")
code.putln(
"return r;")
code.putln(
"}")
def generate_ass_subscript_function(self, scope, code):
# Setting and deleting an item are both done through
# the ass_subscript method, so we dispatch to user's __setitem__
# or __delitem__, or raise an exception.
base_type = scope.parent_type.base_type
set_entry = scope.lookup_here("__setitem__")
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"))
code.putln(
"if (v) {")
if set_entry:
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,")
code.putln(
' "Subscript assignment not supported by %s", Py_TYPE(o)->tp_name);')
code.putln(
"return -1;")
code.putln(
"}")
code.putln(
"else {")
if del_entry:
code.putln(
"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,")
code.putln(
' "Subscript deletion not supported by %s", Py_TYPE(o)->tp_name);')
code.putln(
"return -1;")
code.putln(
"}")
code.putln(
"}")
def generate_guarded_basetype_call(
self, base_type, substructure, slot, args, code):
if base_type:
base_tpname = base_type.typeptr_cname
if substructure:
code.putln(
"if (%s->%s && %s->%s->%s)" % (
base_tpname, substructure, base_tpname, substructure, slot))
code.putln(
" return %s->%s->%s(%s);" % (
base_tpname, substructure, slot, args))
else:
code.putln(
"if (%s->%s)" % (
base_tpname, slot))
code.putln(
" return %s->%s(%s);" % (
base_tpname, slot, args))
def generate_ass_slice_function(self, scope, code):
# Setting and deleting a slice are both done through
# the ass_slice method, so we dispatch to user's __setslice__
# or __delslice__, or raise an exception.
base_type = scope.parent_type.base_type
set_entry = scope.lookup_here("__setslice__")
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"))
code.putln(
"if (v) {")
if set_entry:
code.putln(
"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,")
code.putln(
' "2-element slice assignment not supported by %s", Py_TYPE(o)->tp_name);')
code.putln(
"return -1;")
code.putln(
"}")
code.putln(
"else {")
if del_entry:
code.putln(
"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,")
code.putln(
' "2-element slice deletion not supported by %s", Py_TYPE(o)->tp_name);')
code.putln(
"return -1;")
code.putln(
"}")
code.putln(
"}")
def generate_getattro_function(self, scope, code):
# First try to get the attribute using __getattribute__, if defined, or
# PyObject_GenericGetAttr.
#
# If that raises an AttributeError, call the __getattr__ if defined.
#
# In both cases, defined can be in this class, or any base class.
def lookup_here_or_base(n,type=None):
# Recursive lookup
if type is None:
type = scope.parent_type
r = type.scope.lookup_here(n)
if r is None and \
type.base_type is not None:
return lookup_here_or_base(n,type.base_type)
else:
return r
getattr_entry = lookup_here_or_base("__getattr__")
getattribute_entry = lookup_here_or_base("__getattribute__")
code.putln("")
code.putln(
"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)
else:
code.putln(
"PyObject *v = PyObject_GenericGetAttr(o, n);")
if getattr_entry is not None:
code.putln(
"if (!v && PyErr_ExceptionMatches(PyExc_AttributeError)) {")
code.putln(
"PyErr_Clear();")
code.putln(
"v = %s(o, n);" %
getattr_entry.func_cname)
code.putln(
"}")
code.putln(
"return v;")
code.putln(
"}")
def generate_setattro_function(self, scope, code):
# Setting and deleting an attribute are both done through
# the setattro method, so we dispatch to user's __setattr__
# or __delattr__ or fall back on PyObject_GenericSetAttr.
base_type = scope.parent_type.base_type
set_entry = scope.lookup_here("__setattr__")
del_entry = scope.lookup_here("__delattr__")
code.putln("")
code.putln(
"static int %s(PyObject *o, PyObject *n, PyObject *v) {" %
scope.mangle_internal("tp_setattro"))
code.putln(
"if (v) {")
if set_entry:
code.putln(
"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);")
code.putln(
"}")
code.putln(
"else {")
if del_entry:
code.putln(
"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);")
code.putln(
"}")
code.putln(
"}")
def generate_descr_get_function(self, scope, code):
# The __get__ function of a descriptor object can be
# called with NULL for the second or third arguments
# under some circumstances, so we replace them with
# None in that case.
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"))
code.putln(
"PyObject *r = 0;")
code.putln(
"if (!i) i = Py_None;")
code.putln(
"if (!c) c = Py_None;")
#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)
#code.put_decref("i", py_object_type)
#code.put_decref("c", py_object_type)
code.putln(
"return r;")
code.putln(
"}")
def generate_descr_set_function(self, scope, code):
# Setting and deleting are both done through the __set__
# method of a descriptor, so we dispatch to user's __set__
# or __delete__ or raise an exception.
base_type = scope.parent_type.base_type
user_set_entry = scope.lookup_here("__set__")
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"))
code.putln(
"if (v) {")
if user_set_entry:
code.putln(
"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__");')
code.putln(
"return -1;")
code.putln(
"}")
code.putln(
"else {")
if user_del_entry:
code.putln(
"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__");')
code.putln(
"return -1;")
code.putln(
"}")
code.putln(
"}")
def generate_property_accessors(self, cclass_scope, code):
for entry in cclass_scope.property_entries:
property_scope = entry.scope
if property_scope.defines_any(["__get__"]):
self.generate_property_get_function(entry, code)
if property_scope.defines_any(["__set__", "__del__"]):
self.generate_property_set_function(entry, code)
def generate_property_get_function(self, property_entry, code):
property_scope = property_entry.scope
property_entry.getter_cname = property_scope.parent_scope.mangle(
Naming.prop_get_prefix, property_entry.name)
get_entry = property_scope.lookup_here("__get__")
code.putln("")
code.putln(
"static PyObject *%s(PyObject *o, void *x) {" %
property_entry.getter_cname)
code.putln(
"return %s(o);" %
get_entry.func_cname)
code.putln(
"}")
def generate_property_set_function(self, property_entry, code):
property_scope = property_entry.scope
property_entry.setter_cname = property_scope.parent_scope.mangle(
Naming.prop_set_prefix, property_entry.name)
set_entry = property_scope.lookup_here("__set__")
del_entry = property_scope.lookup_here("__del__")
code.putln("")
code.putln(
"static int %s(PyObject *o, PyObject *v, void *x) {" %
property_entry.setter_cname)
code.putln(
"if (v) {")
if set_entry:
code.putln(
"return %s(o, v);" %
set_entry.func_cname)
else:
code.putln(
'PyErr_SetString(PyExc_NotImplementedError, "__set__");')
code.putln(
"return -1;")
code.putln(
"}")
code.putln(
"else {")
if del_entry:
code.putln(
"return %s(o);" %
del_entry.func_cname)
else:
code.putln(
'PyErr_SetString(PyExc_NotImplementedError, "__del__");')
code.putln(
"return -1;")
code.putln(
"}")
code.putln(
"}")
def generate_typeobj_definition(self, modname, entry, code):
type = entry.type
scope = type.scope
for suite in TypeSlots.substructures:
suite.generate_substructure(scope, code)
code.putln("")
if entry.visibility == 'public':
header = "DL_EXPORT(PyTypeObject) %s = {"
else:
#header = "statichere PyTypeObject %s = {"
header = "PyTypeObject %s = {"
#code.putln(header % scope.parent_type.typeobj_cname)
code.putln(header % type.typeobj_cname)
code.putln(
"PyVarObject_HEAD_INIT(0, 0)")
code.putln(
'__Pyx_NAMESTR("%s.%s"), /*tp_name*/' % (
self.full_module_name, scope.class_name))
if type.typedef_flag:
objstruct = type.objstruct_cname
else:
objstruct = "struct %s" % type.objstruct_cname
code.putln(
"sizeof(%s), /*tp_basicsize*/" %
objstruct)
code.putln(
"0, /*tp_itemsize*/")
for slot in TypeSlots.slot_table:
slot.generate(scope, code)
code.putln(
"};")
def generate_method_table(self, env, code):
code.putln("")
code.putln(
"static PyMethodDef %s[] = {" %
env.method_table_cname)
for entry in env.pyfunc_entries:
code.put_pymethoddef(entry, ",")
code.putln(
"{0, 0, 0, 0}")
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)
for entry in env.property_entries:
if entry.doc:
doc_code = "__Pyx_DOCSTR(%s)" % code.get_string_const(entry.doc)
else:
doc_code = "0"
code.putln(
'{(char *)"%s", %s, %s, %s, 0},' % (
entry.name,
entry.getter_cname or "0",
entry.setter_cname or "0",
doc_code))
code.putln(
"{0, 0, 0, 0, 0}")
code.putln(
"};")
def generate_import_star(self, env, code):
env.use_utility_code(streq_utility_code)
code.putln()
code.putln("char* %s_type_names[] = {" % Naming.import_star)
for name, entry in env.entries.items():
if entry.is_type:
code.putln('"%s",' % name)
code.putln("0")
code.putln("};")
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("char** type_name = %s_type_names;" % Naming.import_star)
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);')
code.putln('goto bad;')
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"
for name, entry in env.entries.items():
if entry.is_cglobal and entry.used:
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:
code.putln("if (!(%s)) %s;" % (
entry.type.type_test_code("o"),
code.error_goto(entry.pos)))
code.put_var_decref(entry)
code.putln("%s = %s;" % (
entry.cname,
PyrexTypes.typecast(entry.type, py_object_type, "o")))
elif entry.type.from_py_function:
rhs = "%s(o)" % entry.type.from_py_function
if entry.type.is_enum:
rhs = typecast(entry.type, c_long_type, rhs)
code.putln("%s = %s; if (%s) %s;" % (
entry.cname,
rhs,
entry.type.error_condition(entry.cname),
code.error_goto(entry.pos)))
code.putln("Py_DECREF(o);")
else:
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 {")
code.putln("if (PyObject_SetAttr(%s, py_name, o) < 0) goto bad;" % Naming.module_cname)
code.putln("}")
code.putln("return 0;")
code.put_label(code.error_label)
# This helps locate the offending name.
code.putln('__Pyx_AddTraceback("%s");' % self.full_module_name);
code.error_label = old_error_label
code.putln("bad:")
code.putln("Py_DECREF(o);")
code.putln("return -1;")
code.putln("}")
code.putln(import_star_utility_code)
code.exit_cfunc_scope() # done with labels
def generate_module_init_func(self, imported_modules, env, code):
code.enter_cfunc_scope()
code.putln("")
header2 = "PyMODINIT_FUNC init%s(void)" % env.module_name
header3 = "PyMODINIT_FUNC PyInit_%s(void)" % env.module_name
code.putln("#if PY_MAJOR_VERSION < 3")
code.putln("%s; /*proto*/" % header2)
code.putln(header2)
code.putln("#else")
code.putln("%s; /*proto*/" % header3)
code.putln(header3)
code.putln("#endif")
code.putln("{")
tempdecl_code = code.insertion_point()
code.putln("#if CYTHON_REFNANNY")
code.putln("void* __pyx_refnanny = NULL;")
code.putln("__Pyx_RefNanny = __Pyx_RefNannyImportAPI(\"refnanny\");")
code.putln("if (!__Pyx_RefNanny) {")
code.putln(" PyErr_Clear();")
code.putln(" __Pyx_RefNanny = __Pyx_RefNannyImportAPI(\"Cython.Runtime.refnanny\");")
code.putln(" if (!__Pyx_RefNanny)")
code.putln(" Py_FatalError(\"failed to import 'refnanny' module\");")
code.putln("}")
code.putln("__pyx_refnanny = __Pyx_RefNanny->SetupContext(\"%s\", __LINE__, __FILE__);"% header3)
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("#ifdef %s_USED" % Naming.binding_cfunc)
code.putln("if (%s_init() < 0) %s" % (Naming.binding_cfunc, code.error_goto(self.pos)))
code.putln("#endif")
code.putln("/*--- Library function declarations ---*/")
env.generate_library_function_declarations(code)
code.putln("/*--- Threads initialization code ---*/")
code.putln("#if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS")
code.putln("#ifdef WITH_THREAD /* Python build with threading support? */")
code.putln("PyEval_InitThreads();")
code.putln("#endif")
code.putln("#endif")
code.putln("/*--- Module creation code ---*/")
self.generate_module_creation_code(env, code)
code.putln("/*--- Initialize various global constants etc. ---*/")
code.putln(code.error_goto_if_neg("__Pyx_InitGlobals()", self.pos))
__main__name = code.globalstate.get_py_string_const(
EncodedString("__main__"), identifier=True)
code.putln("if (%s%s) {" % (Naming.module_is_main, self.full_module_name.replace('.', '__')))
code.putln(
'if (__Pyx_SetAttrString(%s, "__name__", %s) < 0) %s;' % (
env.module_cname,
__main__name.cname,
code.error_goto(self.pos)))
code.putln("}")
if Options.cache_builtins:
code.putln("/*--- Builtin init code ---*/")
code.putln(code.error_goto_if_neg("__Pyx_InitCachedBuiltins()",
self.pos))
code.putln("/*--- Global init code ---*/")
self.generate_global_init_code(env, code)
code.putln("/*--- Function export code ---*/")
self.generate_c_function_export_code(env, code)
code.putln("/*--- Type init code ---*/")
self.generate_type_init_code(env, code)
code.putln("/*--- Type import code ---*/")
for module in imported_modules:
self.generate_type_import_code_for_module(module, env, code)
code.putln("/*--- Function import code ---*/")
for module in imported_modules:
self.generate_c_function_import_code_for_module(module, env, code)
code.putln("/*--- Execution code ---*/")
code.mark_pos(None)
self.body.generate_execution_code(code)
if Options.generate_cleanup_code:
# this should be replaced by the module's tp_clear in Py3
env.use_utility_code(import_module_utility_code)
code.putln("if (__Pyx_RegisterCleanup()) %s;" % code.error_goto(self.pos))
code.put_goto(code.return_label)
code.put_label(code.error_label)
for cname, type in code.funcstate.all_managed_temps():
code.put_xdecref(cname, type)
code.putln('if (%s) {' % env.module_cname)
code.putln('__Pyx_AddTraceback("init %s");' % env.qualified_name)
env.use_utility_code(Nodes.traceback_utility_code)
code.put_decref_clear(env.module_cname, py_object_type, nanny=False)
code.putln('} else if (!PyErr_Occurred()) {')
code.putln('PyErr_SetString(PyExc_ImportError, "init %s");' % env.qualified_name)
code.putln('}')
code.put_label(code.return_label)
code.put_finish_refcount_context()
code.putln("#if PY_MAJOR_VERSION < 3")
code.putln("return;")
code.putln("#else")
code.putln("return %s;" % env.module_cname)
code.putln("#endif")
code.putln('}')
tempdecl_code.put_temp_declarations(code.funcstate)
code.exit_cfunc_scope()
def generate_module_cleanup_func(self, env, code):
if not Options.generate_cleanup_code:
return
code.globalstate.use_utility_code(register_cleanup_utility_code)
code.putln('static PyObject *%s(CYTHON_UNUSED PyObject *self, CYTHON_UNUSED PyObject *unused) {' %
Naming.cleanup_cname)
if Options.generate_cleanup_code >= 2:
code.putln("/*--- Global cleanup code ---*/")
rev_entries = list(env.var_entries)
rev_entries.reverse()
for entry in rev_entries:
if entry.visibility != 'extern':
if entry.type.is_pyobject and entry.used:
code.putln("Py_DECREF(%s); %s = 0;" % (
code.entry_as_pyobject(entry), entry.cname))
code.putln("__Pyx_CleanupGlobals();")
if Options.generate_cleanup_code >= 3:
code.putln("/*--- Type import cleanup code ---*/")
for type, _ in env.types_imported.items():
code.putln("Py_DECREF((PyObject *)%s);" % type.typeptr_cname)
if Options.cache_builtins:
code.putln("/*--- Builtin cleanup code ---*/")
for entry in env.cached_builtins:
code.put_decref_clear(entry.cname,
PyrexTypes.py_object_type,
nanny=False)
code.putln("/*--- Intern cleanup code ---*/")
code.put_decref_clear(Naming.empty_tuple,
PyrexTypes.py_object_type,
nanny=False)
# for entry in env.pynum_entries:
# code.put_decref_clear(entry.cname,
# PyrexTypes.py_object_type,
# nanny=False)
# for entry in env.all_pystring_entries:
# if entry.is_interned:
# code.put_decref_clear(entry.pystring_cname,
# PyrexTypes.py_object_type,
# nanny=False)
# for entry in env.default_entries:
# if entry.type.is_pyobject and entry.used:
# code.putln("Py_DECREF(%s); %s = 0;" % (
# code.entry_as_pyobject(entry), entry.cname))
code.putln("Py_INCREF(Py_None); return Py_None;")
def generate_main_method(self, env, code):
module_is_main = "%s%s" % (Naming.module_is_main, self.full_module_name.replace('.', '__'))
code.globalstate.use_utility_code(main_method.specialize(module_name=env.module_name, module_is_main=module_is_main))
def generate_pymoduledef_struct(self, env, code):
if env.doc:
doc = "__Pyx_DOCSTR(%s)" % code.get_string_const(env.doc)
else:
doc = "0"
code.putln("")
code.putln("#if PY_MAJOR_VERSION >= 3")
code.putln("static struct PyModuleDef %s = {" % Naming.pymoduledef_cname)
code.putln(" PyModuleDef_HEAD_INIT,")
code.putln(' __Pyx_NAMESTR("%s"),' % env.module_name)
code.putln(" %s, /* m_doc */" % doc)
code.putln(" -1, /* m_size */")
code.putln(" %s /* m_methods */," % env.method_table_cname)
code.putln(" NULL, /* m_reload */")
code.putln(" NULL, /* m_traverse */")
code.putln(" NULL, /* m_clear */")
code.putln(" NULL /* m_free */")
code.putln("};")
code.putln("#endif")
def generate_module_creation_code(self, env, code):
# Generate code to create the module object and
# install the builtins.
if env.doc:
doc = "__Pyx_DOCSTR(%s)" % code.get_string_const(env.doc)
else:
doc = "0"
code.putln("#if PY_MAJOR_VERSION < 3")
code.putln(
'%s = Py_InitModule4(__Pyx_NAMESTR("%s"), %s, %s, 0, PYTHON_API_VERSION);' % (
env.module_cname,
env.module_name,
env.method_table_cname,
doc))
code.putln("#else")
code.putln(
"%s = PyModule_Create(&%s);" % (
env.module_cname,
Naming.pymoduledef_cname))
code.putln("#endif")
code.putln(
"if (!%s) %s;" % (
env.module_cname,
code.error_goto(self.pos)));
code.putln("#if PY_MAJOR_VERSION < 3")
code.putln(
"Py_INCREF(%s);" %
env.module_cname)
code.putln("#endif")
code.putln(
'%s = PyImport_AddModule(__Pyx_NAMESTR(__Pyx_BUILTIN_MODULE_NAME));' %
Naming.builtins_cname)
code.putln(
"if (!%s) %s;" % (
Naming.builtins_cname,
code.error_goto(self.pos)));
code.putln(
'if (__Pyx_SetAttrString(%s, "__builtins__", %s) < 0) %s;' % (
env.module_cname,
Naming.builtins_cname,
code.error_goto(self.pos)))
if Options.pre_import is not None:
code.putln(
'%s = PyImport_AddModule(__Pyx_NAMESTR("%s"));' % (
Naming.preimport_cname,
Options.pre_import))
code.putln(
"if (!%s) %s;" % (
Naming.preimport_cname,
code.error_goto(self.pos)));
def generate_global_init_code(self, env, code):
# Generate code to initialise global PyObject *
# variables to None.
for entry in env.var_entries:
if entry.visibility != 'extern':
if entry.type.is_pyobject and entry.used:
code.put_init_var_to_py_none(entry, nanny=False)
def generate_c_function_export_code(self, env, code):
# Generate code to create PyCFunction wrappers for exported C functions.
for entry in env.cfunc_entries:
if entry.api or entry.defined_in_pxd:
env.use_utility_code(function_export_utility_code)
signature = entry.type.signature_string()
code.putln('if (__Pyx_ExportFunction("%s", (void (*)(void))%s, "%s") < 0) %s' % (
entry.name,
entry.cname,
signature,
code.error_goto(self.pos)))
def generate_type_import_code_for_module(self, module, env, code):
# Generate type import code for all exported extension types in
# an imported module.
#if module.c_class_entries:
for entry in module.c_class_entries:
if entry.defined_in_pxd:
self.generate_type_import_code(env, entry.type, entry.pos, code)
def generate_c_function_import_code_for_module(self, module, env, code):
# Generate import code for all exported C functions in a cimported module.
entries = []
for entry in module.cfunc_entries:
if entry.defined_in_pxd:
entries.append(entry)
if entries:
env.use_utility_code(import_module_utility_code)
env.use_utility_code(function_import_utility_code)
temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True)
code.putln(
'%s = __Pyx_ImportModule("%s"); if (!%s) %s' % (
temp,
module.qualified_name,
temp,
code.error_goto(self.pos)))
for entry in entries:
code.putln(
'if (__Pyx_ImportFunction(%s, "%s", (void (**)(void))&%s, "%s") < 0) %s' % (
temp,
entry.name,
entry.cname,
entry.type.signature_string(),
code.error_goto(self.pos)))
code.putln("Py_DECREF(%s); %s = 0;" % (temp, temp))
def generate_type_init_code(self, env, code):
# Generate type import code for extern extension types
# and type ready code for non-extern ones.
for entry in env.c_class_entries:
if entry.visibility == 'extern':
self.generate_type_import_code(env, entry.type, entry.pos, code)
else:
self.generate_base_type_import_code(env, entry, code)
self.generate_exttype_vtable_init_code(entry, code)
self.generate_type_ready_code(env, entry, code)
self.generate_typeptr_assignment_code(entry, code)
def generate_base_type_import_code(self, env, entry, code):
base_type = entry.type.base_type
if base_type and base_type.module_name != env.qualified_name:
self.generate_type_import_code(env, base_type, self.pos, code)
def use_type_import_utility_code(self, env):
env.use_utility_code(type_import_utility_code)
env.use_utility_code(import_module_utility_code)
def generate_type_import_code(self, env, type, pos, code):
# 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.typedef_flag:
objstruct = type.objstruct_cname
else:
objstruct = "struct %s" % type.objstruct_cname
self.generate_type_import_call(type, code,
code.error_goto_if_null(type.typeptr_cname, pos))
self.use_type_import_utility_code(env)
if type.vtabptr_cname:
code.putln(
"if (__Pyx_GetVtable(%s->tp_dict, &%s) < 0) %s" % (
type.typeptr_cname,
type.vtabptr_cname,
code.error_goto(pos)))
env.use_utility_code(Nodes.get_vtable_utility_code)
env.types_imported[type] = 1
py3_type_name_map = {'str' : 'bytes', 'unicode' : 'str'}
def generate_type_import_call(self, type, code, error_code):
if type.typedef_flag:
objstruct = type.objstruct_cname
else:
objstruct = "struct %s" % type.objstruct_cname
module_name = type.module_name
if module_name not in ('__builtin__', 'builtins'):
module_name = '"%s"' % module_name
else:
module_name = '__Pyx_BUILTIN_MODULE_NAME'
if type.name in self.py3_type_name_map:
code.putln("#if PY_MAJOR_VERSION >= 3")
code.putln('%s = __Pyx_ImportType(%s, "%s", sizeof(%s), 1); %s' % (
type.typeptr_cname,
module_name,
self.py3_type_name_map[type.name],
objstruct,
error_code))
code.putln("#else")
code.putln('%s = __Pyx_ImportType(%s, "%s", sizeof(%s), %i); %s' % (
type.typeptr_cname,
module_name,
type.name,
objstruct,
not type.is_external or type.is_subclassed,
error_code))
if type.name in self.py3_type_name_map:
code.putln("#endif")
def generate_type_ready_code(self, env, entry, code):
# Generate a call to PyType_Ready for an extension
# type defined in this module.
type = entry.type
typeobj_cname = type.typeobj_cname
scope = type.scope
if scope: # could be None if there was an error
if entry.visibility != 'extern':
for slot in TypeSlots.slot_table:
slot.generate_dynamic_init_code(scope, code)
code.putln(
"if (PyType_Ready(&%s) < 0) %s" % (
typeobj_cname,
code.error_goto(entry.pos)))
# Fix special method docstrings. This is a bit of a hack, but
# unless we let PyType_Ready create the slot wrappers we have
# a significant performance hit. (See trac #561.)
for func in entry.type.scope.pyfunc_entries:
if func.is_special and func.wrapperbase_cname:
code.putln("{");
code.putln(
'PyObject *wrapper = __Pyx_GetAttrString((PyObject *)&%s, "%s"); %s' % (
typeobj_cname,
func.name,
code.error_goto_if_null('wrapper', entry.pos)));
code.putln(
"if (Py_TYPE(wrapper) == &PyWrapperDescr_Type) {");
code.putln(
"%s = *((PyWrapperDescrObject *)wrapper)->d_base;" % (
func.wrapperbase_cname));
code.putln(
"%s.doc = %s;" % (func.wrapperbase_cname, func.doc_cname));
code.putln(
"((PyWrapperDescrObject *)wrapper)->d_base = &%s;" % (
func.wrapperbase_cname));
code.putln("}");
code.putln("}");
if type.vtable_cname:
code.putln(
"if (__Pyx_SetVtable(%s.tp_dict, %s) < 0) %s" % (
typeobj_cname,
type.vtabptr_cname,
code.error_goto(entry.pos)))
env.use_utility_code(Nodes.set_vtable_utility_code)
code.putln(
'if (__Pyx_SetAttrString(%s, "%s", (PyObject *)&%s) < 0) %s' % (
Naming.module_cname,
scope.class_name,
typeobj_cname,
code.error_goto(entry.pos)))
weakref_entry = scope.lookup_here("__weakref__")
if weakref_entry:
if weakref_entry.type is py_object_type:
tp_weaklistoffset = "%s.tp_weaklistoffset" % typeobj_cname
if type.typedef_flag:
objstruct = type.objstruct_cname
else:
objstruct = "struct %s" % type.objstruct_cname
code.putln("if (%s == 0) %s = offsetof(%s, %s);" % (
tp_weaklistoffset,
tp_weaklistoffset,
objstruct,
weakref_entry.cname))
else:
error(weakref_entry.pos, "__weakref__ slot must be of type 'object'")
def generate_exttype_vtable_init_code(self, entry, code):
# Generate code to initialise the C method table of an
# extension type.
type = entry.type
if type.vtable_cname:
code.putln(
"%s = &%s;" % (
type.vtabptr_cname,
type.vtable_cname))
if type.base_type and type.base_type.vtabptr_cname:
code.putln(
"%s.%s = *%s;" % (
type.vtable_cname,
Naming.obj_base_cname,
type.base_type.vtabptr_cname))
c_method_entries = [
entry for entry in type.scope.cfunc_entries
if entry.func_cname ]
if c_method_entries:
for meth_entry in c_method_entries:
cast = meth_entry.type.signature_cast_string()
code.putln(
"%s.%s = %s%s;" % (
type.vtable_cname,
meth_entry.cname,
cast,
meth_entry.func_cname))
def generate_typeptr_assignment_code(self, entry, code):
# Generate code to initialise the typeptr of an extension
# type defined in this module to point to its type object.
type = entry.type
if type.typeobj_cname:
code.putln(
"%s = &%s;" % (
type.typeptr_cname, type.typeobj_cname))
#------------------------------------------------------------------------------------
#
# Runtime support code
#
#------------------------------------------------------------------------------------
streq_utility_code = UtilityCode(
proto = """
static CYTHON_INLINE int __Pyx_StrEq(const char *, const char *); /*proto*/
""",
impl = """
static CYTHON_INLINE int __Pyx_StrEq(const char *s1, const char *s2) {
while (*s1 != '\\0' && *s1 == *s2) { s1++; s2++; }
return *s1 == *s2;
}
""")
#------------------------------------------------------------------------------------
import_module_utility_code = UtilityCode(
proto = """
static PyObject *__Pyx_ImportModule(const char *name); /*proto*/
""",
impl = """
#ifndef __PYX_HAVE_RT_ImportModule
#define __PYX_HAVE_RT_ImportModule
static PyObject *__Pyx_ImportModule(const char *name) {
PyObject *py_name = 0;
PyObject *py_module = 0;
#if PY_MAJOR_VERSION < 3
py_name = PyString_FromString(name);
#else
py_name = PyUnicode_FromString(name);
#endif
if (!py_name)
goto bad;
py_module = PyImport_Import(py_name);
Py_DECREF(py_name);
return py_module;
bad:
Py_XDECREF(py_name);
return 0;
}
#endif
""")
#------------------------------------------------------------------------------------
type_import_utility_code = UtilityCode(
proto = """
static PyTypeObject *__Pyx_ImportType(const char *module_name, const char *class_name, long size, int strict); /*proto*/
""",
impl = """
#ifndef __PYX_HAVE_RT_ImportType
#define __PYX_HAVE_RT_ImportType
static PyTypeObject *__Pyx_ImportType(const char *module_name, const char *class_name,
long size, int strict)
{
PyObject *py_module = 0;
PyObject *result = 0;
PyObject *py_name = 0;
char warning[200];
py_module = __Pyx_ImportModule(module_name);
if (!py_module)
goto bad;
#if PY_MAJOR_VERSION < 3
py_name = PyString_FromString(class_name);
#else
py_name = PyUnicode_FromString(class_name);
#endif
if (!py_name)
goto bad;
result = PyObject_GetAttr(py_module, py_name);
Py_DECREF(py_name);
py_name = 0;
Py_DECREF(py_module);
py_module = 0;
if (!result)
goto bad;
if (!PyType_Check(result)) {
PyErr_Format(PyExc_TypeError,
"%s.%s is not a type object",
module_name, class_name);
goto bad;
}
if (!strict && ((PyTypeObject *)result)->tp_basicsize > size) {
PyOS_snprintf(warning, sizeof(warning),
"%s.%s size changed, may indicate binary incompatibility",
module_name, class_name);
#if PY_VERSION_HEX < 0x02050000
PyErr_Warn(NULL, warning);
#else
PyErr_WarnEx(NULL, warning, 0);
#endif
}
else if (((PyTypeObject *)result)->tp_basicsize != size) {
PyErr_Format(PyExc_ValueError,
"%s.%s has the wrong size, try recompiling",
module_name, class_name);
goto bad;
}
return (PyTypeObject *)result;
bad:
Py_XDECREF(py_module);
Py_XDECREF(result);
return 0;
}
#endif
""")
#------------------------------------------------------------------------------------
function_export_utility_code = UtilityCode(
proto = """
static int __Pyx_ExportFunction(const char *name, void (*f)(void), const char *sig); /*proto*/
""",
impl = r"""
static int __Pyx_ExportFunction(const char *name, void (*f)(void), const char *sig) {
PyObject *d = 0;
PyObject *cobj = 0;
union {
void (*fp)(void);
void *p;
} tmp;
d = PyObject_GetAttrString(%(MODULE)s, (char *)"%(API)s");
if (!d) {
PyErr_Clear();
d = PyDict_New();
if (!d)
goto bad;
Py_INCREF(d);
if (PyModule_AddObject(%(MODULE)s, (char *)"%(API)s", d) < 0)
goto bad;
}
tmp.fp = f;
#if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0)
cobj = PyCapsule_New(tmp.p, sig, 0);
#else
cobj = PyCObject_FromVoidPtrAndDesc(tmp.p, (void *)sig, 0);
#endif
if (!cobj)
goto bad;
if (PyDict_SetItemString(d, name, cobj) < 0)
goto bad;
Py_DECREF(cobj);
Py_DECREF(d);
return 0;
bad:
Py_XDECREF(cobj);
Py_XDECREF(d);
return -1;
}
""" % {'MODULE': Naming.module_cname, 'API': Naming.api_name}
)
function_import_utility_code = UtilityCode(
proto = """
static int __Pyx_ImportFunction(PyObject *module, const char *funcname, void (**f)(void), const char *sig); /*proto*/
""",
impl = """
#ifndef __PYX_HAVE_RT_ImportFunction
#define __PYX_HAVE_RT_ImportFunction
static int __Pyx_ImportFunction(PyObject *module, const char *funcname, void (**f)(void), const char *sig) {
PyObject *d = 0;
PyObject *cobj = 0;
union {
void (*fp)(void);
void *p;
} tmp;
d = PyObject_GetAttrString(module, (char *)"%(API)s");
if (!d)
goto bad;
cobj = PyDict_GetItemString(d, funcname);
if (!cobj) {
PyErr_Format(PyExc_ImportError,
"%%s does not export expected C function %%s",
PyModule_GetName(module), funcname);
goto bad;
}
#if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0)
if (!PyCapsule_IsValid(cobj, sig)) {
PyErr_Format(PyExc_TypeError,
"C function %%s.%%s has wrong signature (expected %%s, got %%s)",
PyModule_GetName(module), funcname, sig, PyCapsule_GetName(cobj));
goto bad;
}
tmp.p = PyCapsule_GetPointer(cobj, sig);
#else
{const char *desc, *s1, *s2;
desc = (const char *)PyCObject_GetDesc(cobj);
if (!desc)
goto bad;
s1 = desc; s2 = sig;
while (*s1 != '\\0' && *s1 == *s2) { s1++; s2++; }
if (*s1 != *s2) {
PyErr_Format(PyExc_TypeError,
"C function %%s.%%s has wrong signature (expected %%s, got %%s)",
PyModule_GetName(module), funcname, sig, desc);
goto bad;
}
tmp.p = PyCObject_AsVoidPtr(cobj);}
#endif
*f = tmp.fp;
if (!(*f))
goto bad;
Py_DECREF(d);
return 0;
bad:
Py_XDECREF(d);
return -1;
}
#endif
""" % dict(API = Naming.api_name)
)
#------------------------------------------------------------------------------------
register_cleanup_utility_code = UtilityCode(
proto = """
static int __Pyx_RegisterCleanup(void); /*proto*/
static PyObject* %(module_cleanup)s(CYTHON_UNUSED PyObject *self, CYTHON_UNUSED PyObject *unused); /*proto*/
static PyMethodDef cleanup_def = {__Pyx_NAMESTR("__cleanup"), (PyCFunction)&%(module_cleanup)s, METH_NOARGS, 0};
""" % {'module_cleanup': Naming.cleanup_cname},
impl = """
static int __Pyx_RegisterCleanup(void) {
/* Don't use Py_AtExit because that has a 32-call limit
* and is called after python finalization.
*/
PyObject *cleanup_func = 0;
PyObject *atexit = 0;
PyObject *reg = 0;
PyObject *args = 0;
PyObject *res = 0;
int ret = -1;
cleanup_func = PyCFunction_New(&cleanup_def, 0);
args = PyTuple_New(1);
if (!cleanup_func || !args)
goto bad;
PyTuple_SET_ITEM(args, 0, cleanup_func);
cleanup_func = 0;
atexit = __Pyx_ImportModule("atexit");
if (!atexit)
goto bad;
reg = __Pyx_GetAttrString(atexit, "register");
if (!reg)
goto bad;
res = PyObject_CallObject(reg, args);
if (!res)
goto bad;
ret = 0;
bad:
Py_XDECREF(cleanup_func);
Py_XDECREF(atexit);
Py_XDECREF(reg);
Py_XDECREF(args);
Py_XDECREF(res);
return ret;
}
""")
import_star_utility_code = """
/* import_all_from is an unexposed function from ceval.c */
static int
__Pyx_import_all_from(PyObject *locals, PyObject *v)
{
PyObject *all = __Pyx_GetAttrString(v, "__all__");
PyObject *dict, *name, *value;
int skip_leading_underscores = 0;
int pos, err;
if (all == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return -1; /* Unexpected error */
PyErr_Clear();
dict = __Pyx_GetAttrString(v, "__dict__");
if (dict == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return -1;
PyErr_SetString(PyExc_ImportError,
"from-import-* object has no __dict__ and no __all__");
return -1;
}
all = PyMapping_Keys(dict);
Py_DECREF(dict);
if (all == NULL)
return -1;
skip_leading_underscores = 1;
}
for (pos = 0, err = 0; ; pos++) {
name = PySequence_GetItem(all, pos);
if (name == NULL) {
if (!PyErr_ExceptionMatches(PyExc_IndexError))
err = -1;
else
PyErr_Clear();
break;
}
if (skip_leading_underscores &&
#if PY_MAJOR_VERSION < 3
PyString_Check(name) &&
PyString_AS_STRING(name)[0] == '_')
#else
PyUnicode_Check(name) &&
PyUnicode_AS_UNICODE(name)[0] == '_')
#endif
{
Py_DECREF(name);
continue;
}
value = PyObject_GetAttr(v, name);
if (value == NULL)
err = -1;
else if (PyDict_CheckExact(locals))
err = PyDict_SetItem(locals, name, value);
else
err = PyObject_SetItem(locals, name, value);
Py_DECREF(name);
Py_XDECREF(value);
if (err != 0)
break;
}
Py_DECREF(all);
return err;
}
static int %(IMPORT_STAR)s(PyObject* m) {
int i;
int ret = -1;
char* s;
PyObject *locals = 0;
PyObject *list = 0;
#if PY_MAJOR_VERSION >= 3
PyObject *utf8_name = 0;
#endif
PyObject *name;
PyObject *item;
locals = PyDict_New(); if (!locals) goto bad;
if (__Pyx_import_all_from(locals, m) < 0) goto bad;
list = PyDict_Items(locals); if (!list) goto bad;
for(i=0; i= 3
utf8_name = PyUnicode_AsUTF8String(name);
if (!utf8_name) goto bad;
s = PyBytes_AS_STRING(utf8_name);
if (%(IMPORT_STAR_SET)s(item, name, s) < 0) goto bad;
Py_DECREF(utf8_name); utf8_name = 0;
#else
s = PyString_AsString(name);
if (!s) goto bad;
if (%(IMPORT_STAR_SET)s(item, name, s) < 0) goto bad;
#endif
}
ret = 0;
bad:
Py_XDECREF(locals);
Py_XDECREF(list);
#if PY_MAJOR_VERSION >= 3
Py_XDECREF(utf8_name);
#endif
return ret;
}
""" % {'IMPORT_STAR' : Naming.import_star,
'IMPORT_STAR_SET' : Naming.import_star_set }
refnanny_utility_code = UtilityCode(proto="""
#ifndef CYTHON_REFNANNY
#define CYTHON_REFNANNY 0
#endif
#if CYTHON_REFNANNY
typedef struct {
void (*INCREF)(void*, PyObject*, int);
void (*DECREF)(void*, PyObject*, int);
void (*GOTREF)(void*, PyObject*, int);
void (*GIVEREF)(void*, PyObject*, int);
void* (*SetupContext)(const char*, int, const char*);
void (*FinishContext)(void**);
} __Pyx_RefNannyAPIStruct;
static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL;
static __Pyx_RefNannyAPIStruct * __Pyx_RefNannyImportAPI(const char *modname) {
PyObject *m = NULL, *p = NULL;
void *r = NULL;
m = PyImport_ImportModule((char *)modname);
if (!m) goto end;
p = PyObject_GetAttrString(m, (char *)\"RefNannyAPI\");
if (!p) goto end;
r = PyLong_AsVoidPtr(p);
end:
Py_XDECREF(p);
Py_XDECREF(m);
return (__Pyx_RefNannyAPIStruct *)r;
}
#define __Pyx_RefNannySetupContext(name) \
void *__pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__)
#define __Pyx_RefNannyFinishContext() \
__Pyx_RefNanny->FinishContext(&__pyx_refnanny)
#define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
#define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
#define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
#define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
#define __Pyx_XDECREF(r) do { if((r) != NULL) {__Pyx_DECREF(r);} } while(0)
#else
#define __Pyx_RefNannySetupContext(name)
#define __Pyx_RefNannyFinishContext()
#define __Pyx_INCREF(r) Py_INCREF(r)
#define __Pyx_DECREF(r) Py_DECREF(r)
#define __Pyx_GOTREF(r)
#define __Pyx_GIVEREF(r)
#define __Pyx_XDECREF(r) Py_XDECREF(r)
#endif /* CYTHON_REFNANNY */
#define __Pyx_XGIVEREF(r) do { if((r) != NULL) {__Pyx_GIVEREF(r);} } while(0)
#define __Pyx_XGOTREF(r) do { if((r) != NULL) {__Pyx_GOTREF(r);} } while(0)
""")
main_method = UtilityCode(
impl = """
#ifdef __FreeBSD__
#include
#endif
#if PY_MAJOR_VERSION < 3
int main(int argc, char** argv) {
#elif defined(WIN32) || defined(MS_WINDOWS)
int wmain(int argc, wchar_t **argv) {
#else
static int __Pyx_main(int argc, wchar_t **argv) {
#endif
int r = 0;
PyObject* m = NULL;
/* 754 requires that FP exceptions run in "no stop" mode by default,
* and until C vendors implement C99's ways to control FP exceptions,
* Python requires non-stop mode. Alas, some platforms enable FP
* exceptions by default. Here we disable them.
*/
#ifdef __FreeBSD__
fp_except_t m;
m = fpgetmask();
fpsetmask(m & ~FP_X_OFL);
#endif
Py_SetProgramName(argv[0]);
Py_Initialize();
PySys_SetArgv(argc, argv);
%(module_is_main)s = 1;
#if PY_MAJOR_VERSION < 3
init%(module_name)s();
#else
m = PyInit_%(module_name)s();
#endif
if (PyErr_Occurred() != NULL) {
r = 1;
PyErr_Print(); /* This exits with the right code if SystemExit. */
#if PY_MAJOR_VERSION < 3
if (Py_FlushLine()) PyErr_Clear();
#endif
}
Py_XDECREF(m);
Py_Finalize();
return r;
}
#if PY_MAJOR_VERSION >= 3 && !defined(WIN32) && !defined(MS_WINDOWS)
#include
static wchar_t*
__Pyx_char2wchar(char* arg)
{
wchar_t *res;
#ifdef HAVE_BROKEN_MBSTOWCS
/* Some platforms have a broken implementation of
* mbstowcs which does not count the characters that
* would result from conversion. Use an upper bound.
*/
size_t argsize = strlen(arg);
#else
size_t argsize = mbstowcs(NULL, arg, 0);
#endif
size_t count;
unsigned char *in;
wchar_t *out;
#ifdef HAVE_MBRTOWC
mbstate_t mbs;
#endif
if (argsize != (size_t)-1) {
res = (wchar_t *)malloc((argsize+1)*sizeof(wchar_t));
if (!res)
goto oom;
count = mbstowcs(res, arg, argsize+1);
if (count != (size_t)-1) {
wchar_t *tmp;
/* Only use the result if it contains no
surrogate characters. */
for (tmp = res; *tmp != 0 &&
(*tmp < 0xd800 || *tmp > 0xdfff); tmp++)
;
if (*tmp == 0)
return res;
}
free(res);
}
/* Conversion failed. Fall back to escaping with surrogateescape. */
#ifdef HAVE_MBRTOWC
/* Try conversion with mbrtwoc (C99), and escape non-decodable bytes. */
/* Overallocate; as multi-byte characters are in the argument, the
actual output could use less memory. */
argsize = strlen(arg) + 1;
res = malloc(argsize*sizeof(wchar_t));
if (!res) goto oom;
in = (unsigned char*)arg;
out = res;
memset(&mbs, 0, sizeof mbs);
while (argsize) {
size_t converted = mbrtowc(out, (char*)in, argsize, &mbs);
if (converted == 0)
/* Reached end of string; null char stored. */
break;
if (converted == (size_t)-2) {
/* Incomplete character. This should never happen,
since we provide everything that we have -
unless there is a bug in the C library, or I
misunderstood how mbrtowc works. */
fprintf(stderr, "unexpected mbrtowc result -2\\n");
return NULL;
}
if (converted == (size_t)-1) {
/* Conversion error. Escape as UTF-8b, and start over
in the initial shift state. */
*out++ = 0xdc00 + *in++;
argsize--;
memset(&mbs, 0, sizeof mbs);
continue;
}
if (*out >= 0xd800 && *out <= 0xdfff) {
/* Surrogate character. Escape the original
byte sequence with surrogateescape. */
argsize -= converted;
while (converted--)
*out++ = 0xdc00 + *in++;
continue;
}
/* successfully converted some bytes */
in += converted;
argsize -= converted;
out++;
}
#else
/* Cannot use C locale for escaping; manually escape as if charset
is ASCII (i.e. escape all bytes > 128. This will still roundtrip
correctly in the locale's charset, which must be an ASCII superset. */
res = malloc((strlen(arg)+1)*sizeof(wchar_t));
if (!res) goto oom;
in = (unsigned char*)arg;
out = res;
while(*in)
if(*in < 128)
*out++ = *in++;
else
*out++ = 0xdc00 + *in++;
*out = 0;
#endif
return res;
oom:
fprintf(stderr, "out of memory\\n");
return NULL;
}
int
main(int argc, char **argv)
{
wchar_t **argv_copy = (wchar_t **)malloc(sizeof(wchar_t*)*argc);
/* We need a second copies, as Python might modify the first one. */
wchar_t **argv_copy2 = (wchar_t **)malloc(sizeof(wchar_t*)*argc);
int i, res;
char *oldloc;
if (!argv_copy || !argv_copy2) {
fprintf(stderr, "out of memory\\n");
return 1;
}
oldloc = strdup(setlocale(LC_ALL, NULL));
setlocale(LC_ALL, "");
for (i = 0; i < argc; i++) {
argv_copy2[i] = argv_copy[i] = __Pyx_char2wchar(argv[i]);
if (!argv_copy[i])
return 1;
}
setlocale(LC_ALL, oldloc);
free(oldloc);
res = __Pyx_main(argc, argv_copy);
for (i = 0; i < argc; i++) {
free(argv_copy2[i]);
}
free(argv_copy);
free(argv_copy2);
return res;
}
#endif
""")
packed_struct_utility_code = UtilityCode(proto="""
#if defined(__GNUC__)
#define __Pyx_PACKED __attribute__((__packed__))
#else
#define __Pyx_PACKED
#endif
""", impl="", proto_block='utility_code_proto_before_types')
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Naming.py 0000664 0000000 0000000 00000010704 11446142532 0024547 0 ustar 00root root 0000000 0000000 #
# Pyrex - C naming conventions
#
#
# Prefixes for generating C names.
# Collected here to facilitate ensuring uniqueness.
#
pyrex_prefix = "__pyx_"
codewriter_temp_prefix = pyrex_prefix + "t_"
temp_prefix = u"__cyt_"
builtin_prefix = pyrex_prefix + "builtin_"
arg_prefix = pyrex_prefix + "arg_"
funcdoc_prefix = pyrex_prefix + "doc_"
enum_prefix = pyrex_prefix + "e_"
func_prefix = pyrex_prefix + "f_"
pyfunc_prefix = pyrex_prefix + "pf_"
gstab_prefix = pyrex_prefix + "getsets_"
prop_get_prefix = pyrex_prefix + "getprop_"
const_prefix = pyrex_prefix + "k_"
py_const_prefix = pyrex_prefix + "kp_"
label_prefix = pyrex_prefix + "L"
pymethdef_prefix = pyrex_prefix + "mdef_"
methtab_prefix = pyrex_prefix + "methods_"
memtab_prefix = pyrex_prefix + "members_"
interned_str_prefix = pyrex_prefix + "n_"
interned_num_prefix = pyrex_prefix + "int_"
objstruct_prefix = pyrex_prefix + "obj_"
typeptr_prefix = pyrex_prefix + "ptype_"
prop_set_prefix = pyrex_prefix + "setprop_"
type_prefix = pyrex_prefix + "t_"
typeobj_prefix = pyrex_prefix + "type_"
var_prefix = pyrex_prefix + "v_"
wrapperbase_prefix= pyrex_prefix + "wrapperbase_"
bufstruct_prefix = pyrex_prefix + "bstruct_"
bufstride_prefix = pyrex_prefix + "bstride_"
bufshape_prefix = pyrex_prefix + "bshape_"
bufsuboffset_prefix = pyrex_prefix + "boffset_"
vtable_prefix = pyrex_prefix + "vtable_"
vtabptr_prefix = pyrex_prefix + "vtabptr_"
vtabstruct_prefix = pyrex_prefix + "vtabstruct_"
opt_arg_prefix = pyrex_prefix + "opt_args_"
convert_func_prefix = pyrex_prefix + "convert_"
closure_scope_prefix = pyrex_prefix + "scope_"
closure_class_prefix = pyrex_prefix + "scope_struct_"
lambda_func_prefix = pyrex_prefix + "lambda_"
module_is_main = pyrex_prefix + "module_is_main_"
args_cname = pyrex_prefix + "args"
pykwdlist_cname = pyrex_prefix + "pyargnames"
obj_base_cname = pyrex_prefix + "base"
builtins_cname = pyrex_prefix + "b"
preimport_cname = pyrex_prefix + "i"
moddict_cname = pyrex_prefix + "d"
dummy_cname = pyrex_prefix + "dummy"
filename_cname = pyrex_prefix + "filename"
modulename_cname = pyrex_prefix + "modulename"
filetable_cname = pyrex_prefix + "f"
intern_tab_cname = pyrex_prefix + "intern_tab"
kwds_cname = pyrex_prefix + "kwds"
lineno_cname = pyrex_prefix + "lineno"
clineno_cname = pyrex_prefix + "clineno"
cfilenm_cname = pyrex_prefix + "cfilenm"
module_cname = pyrex_prefix + "m"
moddoc_cname = pyrex_prefix + "mdoc"
methtable_cname = pyrex_prefix + "methods"
retval_cname = pyrex_prefix + "r"
reqd_kwds_cname = pyrex_prefix + "reqd_kwds"
self_cname = pyrex_prefix + "self"
stringtab_cname = pyrex_prefix + "string_tab"
vtabslot_cname = pyrex_prefix + "vtab"
c_api_tab_cname = pyrex_prefix + "c_api_tab"
gilstate_cname = pyrex_prefix + "state"
skip_dispatch_cname = pyrex_prefix + "skip_dispatch"
empty_tuple = pyrex_prefix + "empty_tuple"
empty_bytes = pyrex_prefix + "empty_bytes"
print_function = pyrex_prefix + "print"
print_function_kwargs = pyrex_prefix + "print_kwargs"
cleanup_cname = pyrex_prefix + "module_cleanup"
pymoduledef_cname = pyrex_prefix + "moduledef"
optional_args_cname = pyrex_prefix + "optional_args"
import_star = pyrex_prefix + "import_star"
import_star_set = pyrex_prefix + "import_star_set"
outer_scope_cname= pyrex_prefix + "outer_scope"
cur_scope_cname = pyrex_prefix + "cur_scope"
enc_scope_cname = pyrex_prefix + "enc_scope"
frame_cname = pyrex_prefix + "frame"
frame_code_cname = pyrex_prefix + "frame_code"
binding_cfunc = pyrex_prefix + "binding_PyCFunctionType"
genexpr_id_ref = 'genexpr'
line_c_macro = "__LINE__"
file_c_macro = "__FILE__"
extern_c_macro = pyrex_prefix.upper() + "EXTERN_C"
exc_type_name = pyrex_prefix + "exc_type"
exc_value_name = pyrex_prefix + "exc_value"
exc_tb_name = pyrex_prefix + "exc_tb"
exc_lineno_name = pyrex_prefix + "exc_lineno"
exc_vars = (exc_type_name, exc_value_name, exc_tb_name)
exc_save_vars = (pyrex_prefix + 'save_exc_type',
pyrex_prefix + 'save_exc_value',
pyrex_prefix + 'save_exc_tb')
api_name = pyrex_prefix + "capi__"
h_guard_prefix = "__PYX_HAVE__"
api_guard_prefix = "__PYX_HAVE_API__"
api_func_guard = "__PYX_HAVE_API_FUNC_"
def py_version_hex(major, minor=0, micro=0, release_level=0, release_serial=0):
return (major << 24) | (minor << 16) | (micro << 8) | (release_level << 4) | (release_serial)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Nodes.py 0000664 0000000 0000000 00000752504 11446142532 0024421 0 ustar 00root root 0000000 0000000
#
# Pyrex - Parse tree nodes
#
import sys, os, time, copy
try:
set
except NameError:
# Python 2.3
from sets import Set as set
import Code
import Builtin
from Errors import error, warning, InternalError
import Naming
import PyrexTypes
import TypeSlots
from PyrexTypes import py_object_type, error_type, CFuncType
from Symtab import ModuleScope, LocalScope, ClosureScope, \
StructOrUnionScope, PyClassScope, CClassScope, CppClassScope
from Cython.Utils import open_new_file, replace_suffix
from Code import UtilityCode
from StringEncoding import EncodedString, escape_byte_string, split_string_literal
import Options
import ControlFlow
import DebugFlags
absolute_path_length = 0
def relative_position(pos):
"""
We embed the relative filename in the generated C file, since we
don't want to have to regnerate and compile all the source code
whenever the Python install directory moves (which could happen,
e.g,. when distributing binaries.)
INPUT:
a position tuple -- (absolute filename, line number column position)
OUTPUT:
relative filename
line number
AUTHOR: William Stein
"""
global absolute_path_length
if absolute_path_length==0:
absolute_path_length = len(os.path.abspath(os.getcwd()))
return (pos[0].get_filenametable_entry()[absolute_path_length+1:], pos[1])
def embed_position(pos, docstring):
if not Options.embed_pos_in_docstring:
return docstring
pos_line = u'File: %s (starting at line %s)' % relative_position(pos)
if docstring is None:
# unicode string
return EncodedString(pos_line)
# make sure we can encode the filename in the docstring encoding
# otherwise make the docstring a unicode string
encoding = docstring.encoding
if encoding is not None:
try:
encoded_bytes = pos_line.encode(encoding)
except UnicodeEncodeError:
encoding = None
if not docstring:
# reuse the string encoding of the original docstring
doc = EncodedString(pos_line)
else:
doc = EncodedString(pos_line + u'\n' + docstring)
doc.encoding = encoding
return doc
from Code import CCodeWriter
from types import FunctionType
def write_func_call(func):
def f(*args, **kwds):
if len(args) > 1 and isinstance(args[1], CCodeWriter):
# here we annotate the code with this function call
# 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:])
pristine = code.buffer.stream.tell()
code.putln(marker)
start = code.buffer.stream.tell()
code.call_level += 4
res = func(*args, **kwds)
code.call_level -= 4
if start == code.buffer.stream.tell():
code.buffer.stream.seek(pristine)
else:
marker = marker.replace('->', '<-')
code.putln(marker)
return res
else:
return func(*args, **kwds)
return f
class VerboseCodeWriter(type):
# Set this as a metaclass to trace function calls in code.
# This slows down code generation and makes much larger files.
def __new__(cls, name, bases, attrs):
attrs = dict(attrs)
for mname, m in attrs.items():
if isinstance(m, FunctionType):
attrs[mname] = write_func_call(m)
return super(VerboseCodeWriter, cls).__new__(cls, name, bases, attrs)
class Node(object):
# pos (string, int, int) Source file position
# is_name boolean Is a NameNode
# is_literal boolean Is a ConstNode
if DebugFlags.debug_trace_code_generation:
__metaclass__ = VerboseCodeWriter
is_name = 0
is_literal = 0
temps = None
# All descandants should set child_attrs to a list of the attributes
# containing nodes considered "children" in the tree. Each such attribute
# can either contain a single node or a list of nodes. See Visitor.py.
child_attrs = None
def __init__(self, pos, **kw):
self.pos = pos
self.__dict__.update(kw)
gil_message = "Operation"
nogil_check = None
def gil_error(self, env=None):
error(self.pos, "%s not allowed without gil" % self.gil_message)
cpp_message = "Operation"
def cpp_check(self, env):
if not env.is_cpp():
self.cpp_error()
def cpp_error(self):
error(self.pos, "%s only allowed in c++" % self.cpp_message)
def clone_node(self):
"""Clone the node. This is defined as a shallow copy, except for member lists
amongst the child attributes (from get_child_accessors) which are also
copied. Lists containing child nodes are thus seen as a way for the node
to hold multiple children directly; the list is not treated as a seperate
level in the tree."""
result = copy.copy(self)
for attrname in result.child_attrs:
value = getattr(result, attrname)
if isinstance(value, list):
setattr(result, attrname, [x for x in value])
return result
#
# There are 4 phases of parse tree processing, applied in order to
# all the statements in a given scope-block:
#
# (0) analyse_control_flow
# Create the control flow tree into which state can be asserted and
# queried.
#
# (1) analyse_declarations
# Make symbol table entries for all declarations at the current
# level, both explicit (def, cdef, etc.) and implicit (assignment
# to an otherwise undeclared name).
#
# (2) analyse_expressions
# Determine the result types of expressions and fill in the
# 'type' attribute of each ExprNode. Insert coercion nodes into the
# tree where needed to convert to and from Python objects.
# Allocate temporary locals for intermediate results. Fill
# in the 'result_code' attribute of each ExprNode with a C code
# fragment.
#
# (3) generate_code
# Emit C code for all declarations, statements and expressions.
# Recursively applies the 3 processing phases to the bodies of
# functions.
#
def analyse_control_flow(self, env):
pass
def analyse_declarations(self, env):
pass
def analyse_expressions(self, env):
raise InternalError("analyse_expressions not implemented for %s" % \
self.__class__.__name__)
def generate_code(self, code):
raise InternalError("generate_code not implemented for %s" % \
self.__class__.__name__)
def annotate(self, code):
# mro does the wrong thing
if isinstance(self, BlockNode):
self.body.annotate(code)
def end_pos(self):
try:
return self._end_pos
except AttributeError:
pos = self.pos
if not self.child_attrs:
self._end_pos = pos
return pos
for attr in self.child_attrs:
child = getattr(self, attr)
# Sometimes lists, sometimes nodes
if child is None:
pass
elif isinstance(child, list):
for c in child:
pos = max(pos, c.end_pos())
else:
pos = max(pos, child.end_pos())
self._end_pos = pos
return pos
def dump(self, level=0, filter_out=("pos",), cutoff=100, encountered=None):
if cutoff == 0:
return "<...nesting level cutoff...>"
if encountered is None:
encountered = set()
if id(self) in encountered:
return "<%s (%d) -- already output>" % (self.__class__.__name__, id(self))
encountered.add(id(self))
def dump_child(x, level):
if isinstance(x, Node):
return x.dump(level, filter_out, cutoff-1, encountered)
elif isinstance(x, list):
return "[%s]" % ", ".join([dump_child(item, level) for item in x])
else:
return repr(x)
attrs = [(key, value) for key, value in self.__dict__.iteritems() if key not in filter_out]
if len(attrs) == 0:
return "<%s (%d)>" % (self.__class__.__name__, id(self))
else:
indent = " " * level
res = "<%s (%d)\n" % (self.__class__.__name__, id(self))
for key, value in attrs:
res += "%s %s: %s\n" % (indent, key, dump_child(value, level + 1))
res += "%s>" % indent
return res
class CompilerDirectivesNode(Node):
"""
Sets compiler directives for the children nodes
"""
# directives {string:value} A dictionary holding the right value for
# *all* possible directives.
# body Node
child_attrs = ["body"]
def analyse_control_flow(self, env):
old = env.directives
env.directives = self.directives
self.body.analyse_control_flow(env)
env.directives = old
def analyse_declarations(self, env):
old = env.directives
env.directives = self.directives
self.body.analyse_declarations(env)
env.directives = old
def analyse_expressions(self, env):
old = env.directives
env.directives = self.directives
self.body.analyse_expressions(env)
env.directives = old
def generate_function_definitions(self, env, code):
env_old = env.directives
code_old = code.globalstate.directives
code.globalstate.directives = self.directives
self.body.generate_function_definitions(env, code)
env.directives = env_old
code.globalstate.directives = code_old
def generate_execution_code(self, code):
old = code.globalstate.directives
code.globalstate.directives = self.directives
self.body.generate_execution_code(code)
code.globalstate.directives = old
def annotate(self, code):
old = code.globalstate.directives
code.globalstate.directives = self.directives
self.body.annotate(code)
code.globalstate.directives = old
class BlockNode(object):
# Mixin class for nodes representing a declaration block.
def generate_cached_builtins_decls(self, env, code):
entries = env.global_scope().undeclared_cached_builtins
for entry in entries:
code.globalstate.add_cached_builtin_decl(entry)
del entries[:]
class StatListNode(Node):
# stats a list of StatNode
child_attrs = ["stats"]
def create_analysed(pos, env, *args, **kw):
node = StatListNode(pos, *args, **kw)
return node # No node-specific analysis necesarry
create_analysed = staticmethod(create_analysed)
def analyse_control_flow(self, env):
for stat in self.stats:
stat.analyse_control_flow(env)
def analyse_declarations(self, env):
#print "StatListNode.analyse_declarations" ###
for stat in self.stats:
stat.analyse_declarations(env)
def analyse_expressions(self, env):
#print "StatListNode.analyse_expressions" ###
for stat in self.stats:
stat.analyse_expressions(env)
def generate_function_definitions(self, env, code):
#print "StatListNode.generate_function_definitions" ###
for stat in self.stats:
stat.generate_function_definitions(env, code)
def generate_execution_code(self, code):
#print "StatListNode.generate_execution_code" ###
for stat in self.stats:
code.mark_pos(stat.pos)
stat.generate_execution_code(code)
def annotate(self, code):
for stat in self.stats:
stat.annotate(code)
class StatNode(Node):
#
# Code generation for statements is split into the following subphases:
#
# (1) generate_function_definitions
# Emit C code for the definitions of any structs,
# unions, enums and functions defined in the current
# scope-block.
#
# (2) generate_execution_code
# Emit C code for executable statements.
#
def generate_function_definitions(self, env, code):
pass
def generate_execution_code(self, code):
raise InternalError("generate_execution_code not implemented for %s" % \
self.__class__.__name__)
class CDefExternNode(StatNode):
# include_file string or None
# body StatNode
child_attrs = ["body"]
def analyse_declarations(self, env):
if self.include_file:
env.add_include_file(self.include_file)
old_cinclude_flag = env.in_cinclude
env.in_cinclude = 1
self.body.analyse_declarations(env)
env.in_cinclude = old_cinclude_flag
def analyse_expressions(self, env):
pass
def generate_execution_code(self, code):
pass
def annotate(self, code):
self.body.annotate(code)
class CDeclaratorNode(Node):
# Part of a C declaration.
#
# Processing during analyse_declarations phase:
#
# analyse
# Returns (name, type) pair where name is the
# CNameDeclaratorNode of the name being declared
# and type is the type it is being declared as.
#
# calling_convention string Calling convention of CFuncDeclaratorNode
# for which this is a base
child_attrs = []
calling_convention = ""
class CNameDeclaratorNode(CDeclaratorNode):
# name string The Pyrex name being declared
# cname string or None C name, if specified
# default ExprNode or None the value assigned on declaration
child_attrs = ['default']
default = None
def analyse(self, base_type, env, nonempty = 0):
if nonempty and self.name == '':
# May have mistaken the name for the type.
if base_type.is_ptr or base_type.is_array or base_type.is_buffer:
error(self.pos, "Missing argument name")
elif base_type.is_void:
error(self.pos, "Use spam() rather than spam(void) to declare a function with no arguments.")
else:
self.name = base_type.declaration_code("", for_display=1, pyrex=1)
base_type = py_object_type
self.type = base_type
return self, base_type
class CPtrDeclaratorNode(CDeclaratorNode):
# base CDeclaratorNode
child_attrs = ["base"]
def analyse(self, base_type, env, nonempty = 0):
if base_type.is_pyobject:
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)
class CReferenceDeclaratorNode(CDeclaratorNode):
# base CDeclaratorNode
child_attrs = ["base"]
def analyse(self, base_type, env, nonempty = 0):
if base_type.is_pyobject:
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)
class CArrayDeclaratorNode(CDeclaratorNode):
# base CDeclaratorNode
# dimension ExprNode
child_attrs = ["base", "dimension"]
def analyse(self, base_type, env, nonempty = 0):
if base_type.is_cpp_class:
from ExprNodes import TupleNode
if isinstance(self.dimension, TupleNode):
args = self.dimension.args
else:
args = self.dimension,
values = [v.analyse_as_type(env) for v in args]
if None in values:
ix = values.index(None)
error(args[ix].pos, "Template parameter not a type.")
return error_type
base_type = base_type.specialize_here(self.pos, values)
return self.base.analyse(base_type, env, nonempty = nonempty)
if self.dimension:
self.dimension.analyse_const_expression(env)
if not self.dimension.type.is_int:
error(self.dimension.pos, "Array dimension not integer")
size = self.dimension.get_constant_c_result_code()
if size is not None:
try:
size = int(size)
except ValueError:
# runtime constant?
pass
else:
size = None
if not base_type.is_complete():
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")
if base_type.is_cfunction:
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)
class CFuncDeclaratorNode(CDeclaratorNode):
# base CDeclaratorNode
# args [CArgDeclNode]
# has_varargs boolean
# exception_value ConstNode
# exception_check boolean True if PyErr_Occurred check needed
# nogil boolean Can be called without gil
# with_gil boolean Acquire gil around function body
child_attrs = ["base", "args", "exception_value"]
overridable = 0
optional_arg_count = 0
def analyse(self, return_type, env, nonempty = 0):
if nonempty:
nonempty -= 1
func_type_args = []
for arg_node in self.args:
name_declarator, type = arg_node.analyse(env, nonempty = nonempty)
name = name_declarator.name
if name_declarator.cname:
error(self.pos,
"Function argument cannot have C name specification")
# Turn *[] argument into **
if type.is_array:
type = PyrexTypes.c_ptr_type(type.base_type)
# Catch attempted C-style func(void) decl
if type.is_void:
error(arg_node.pos, "Use spam() rather than spam(void) to declare a function with no arguments.")
func_type_args.append(
PyrexTypes.CFuncTypeArg(name, type, arg_node.pos))
if arg_node.default:
self.optional_arg_count += 1
elif self.optional_arg_count:
error(self.pos, "Non-default argument follows default argument")
if self.optional_arg_count:
scope = StructOrUnionScope()
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:]:
scope.declare_var(arg.name, arg.type, arg.pos, allow_pyobject = 1)
struct_cname = env.mangle(Naming.opt_arg_prefix, self.base.name)
self.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)
self.op_args_struct.defined_in_pxd = 1
self.op_args_struct.used = 1
exc_val = None
exc_check = 0
if self.exception_check == '+':
env.add_include_file('stdexcept')
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")
else:
if self.exception_value:
self.exception_value.analyse_const_expression(env)
if self.exception_check == '+':
self.exception_value.analyse_types(env)
exc_val_type = self.exception_value.type
if not exc_val_type.is_error and \
not exc_val_type.is_pyobject and \
not (exc_val_type.is_cfunction and not exc_val_type.return_type.is_pyobject and len(exc_val_type.args)==0):
error(self.exception_value.pos,
"Exception value must be a Python exception or cdef function with no arguments.")
exc_val = self.exception_value
else:
if self.exception_value.analyse_const_expression(env):
exc_val = self.exception_value.get_constant_c_result_code()
if exc_val is None:
raise InternalError("get_constant_c_result_code not implemented for %s" %
self.exception_value.__class__.__name__)
if not return_type.assignable_from(self.exception_value.type):
error(self.exception_value.pos,
"Exception value incompatible with function return type")
exc_check = self.exception_check
if return_type.is_array:
error(self.pos,
"Function cannot return an array")
if return_type.is_cfunction:
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)
if self.optional_arg_count:
func_type.op_arg_struct = PyrexTypes.c_ptr_type(self.op_args_struct.type)
callspec = env.directives['callspec']
if callspec:
current = func_type.calling_convention
if current and current != callspec:
error(self.pos, "cannot have both '%s' and '%s' "
"calling conventions" % (current, callspec))
func_type.calling_convention = callspec
return self.base.analyse(func_type, env)
class CArgDeclNode(Node):
# Item in a function declaration argument list.
#
# base_type CBaseTypeNode
# declarator CDeclaratorNode
# not_none boolean Tagged with 'not None'
# or_none boolean Tagged with 'or None'
# accept_none boolean Resolved boolean for not_none/or_none
# default ExprNode or None
# default_value PyObjectConst constant for default value
# annotation ExprNode or None Py3 function arg annotation
# is_self_arg boolean Is the "self" arg of an extension type method
# is_type_arg boolean Is the "class" arg of an extension type classmethod
# is_kw_only boolean Is a keyword-only argument
child_attrs = ["base_type", "declarator", "default"]
is_self_arg = 0
is_type_arg = 0
is_generic = 1
type = None
name_declarator = None
default_value = None
annotation = None
def analyse(self, env, nonempty = 0):
#print "CArgDeclNode.analyse: is_self_arg =", self.is_self_arg ###
if self.type is None:
# The parser may missinterpret names as types...
# We fix that here.
if isinstance(self.declarator, CNameDeclaratorNode) and self.declarator.name == '':
if nonempty:
self.declarator.name = self.base_type.name
self.base_type.name = None
self.base_type.is_basic_c_type = False
could_be_name = True
else:
could_be_name = False
base_type = self.base_type.analyse(env, could_be_name = could_be_name)
if hasattr(self.base_type, 'arg_name') and self.base_type.arg_name:
self.declarator.name = self.base_type.arg_name
# The parser is unable to resolve the ambiguity of [] as part of the
# type (e.g. in buffers) or empty declarator (as with arrays).
# This is only arises for empty multi-dimensional arrays.
if (base_type.is_array
and isinstance(self.base_type, TemplatedTypeNode)
and isinstance(self.declarator, CArrayDeclaratorNode)):
declarator = self.declarator
while isinstance(declarator.base, CArrayDeclaratorNode):
declarator = declarator.base
declarator.base = self.base_type.array_declarator
base_type = base_type.base_type
return self.declarator.analyse(base_type, env, nonempty = nonempty)
else:
return self.name_declarator, self.type
def calculate_default_value_code(self, code):
if self.default_value is None:
if self.default:
if self.default.is_literal:
# will not output any code, just assign the result_code
self.default.generate_evaluation_code(code)
return self.type.cast_code(self.default.result())
self.default_value = code.get_argument_default_const(self.type)
return self.default_value
def annotate(self, code):
if self.default:
self.default.annotate(code)
class CBaseTypeNode(Node):
# Abstract base class for C base type nodes.
#
# Processing during analyse_declarations phase:
#
# analyse
# Returns the type.
pass
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):
return self.type
class CSimpleBaseTypeNode(CBaseTypeNode):
# name string
# module_path [string] Qualifying name components
# is_basic_c_type boolean
# signed boolean
# longness integer
# complex boolean
# is_self_arg boolean Is self argument of C method
# ##is_type_arg boolean Is type argument of class method
child_attrs = []
arg_name = None # in case the argument name was interpreted as a type
def analyse(self, env, could_be_name = False):
# Return type descriptor.
#print "CSimpleBaseTypeNode.analyse: is_self_arg =", self.is_self_arg ###
type = None
if self.is_basic_c_type:
type = PyrexTypes.simple_c_type(self.signed, self.longness, self.name)
if not type:
error(self.pos, "Unrecognised type modifier combination")
elif self.name == "object" and not self.module_path:
type = py_object_type
elif self.name is None:
if self.is_self_arg and env.is_c_class_scope:
#print "CSimpleBaseTypeNode.analyse: defaulting to parent type" ###
type = env.parent_type
## elif self.is_type_arg and env.is_c_class_scope:
## type = Builtin.type_type
else:
type = py_object_type
else:
if self.module_path:
scope = env.find_imported_module(self.module_path, self.pos)
else:
scope = env
if scope:
if scope.is_c_class_scope:
scope = scope.global_scope()
entry = scope.lookup(self.name)
if entry and entry.is_type:
type = entry.type
elif could_be_name:
if self.is_self_arg and env.is_c_class_scope:
type = env.parent_type
## elif self.is_type_arg and env.is_c_class_scope:
## type = Builtin.type_type
else:
type = py_object_type
self.arg_name = self.name
else:
if self.templates:
if not self.name in self.templates:
error(self.pos, "'%s' is not a type identifier" % self.name)
type = PyrexTypes.TemplatePlaceholderType(self.name)
else:
error(self.pos, "'%s' is not a type identifier" % self.name)
if self.complex:
if not type.is_numeric or type.is_complex:
error(self.pos, "can only complexify c numeric types")
type = PyrexTypes.CComplexType(type)
type.create_declaration_utility_code(env)
if type:
return type
else:
return PyrexTypes.error_type
class CNestedBaseTypeNode(CBaseTypeNode):
# For C++ classes that live inside other C++ classes.
# name string
# base_type CBaseTypeNode
child_attrs = ['base_type']
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
if not base_type.is_cpp_class:
error(self.pos, "'%s' is not a valid type scope" % base_type)
return PyrexTypes.error_type
type_entry = base_type.scope.lookup_here(self.name)
if not type_entry or not type_entry.is_type:
error(self.pos, "'%s.%s' is not a type identifier" % (base_type, self.name))
return PyrexTypes.error_type
return type_entry.type
class TemplatedTypeNode(CBaseTypeNode):
# After parsing:
# positional_args [ExprNode] List of positional arguments
# keyword_args DictNode Keyword arguments
# base_type_node CBaseTypeNode
# After analysis:
# type PyrexTypes.BufferType or PyrexTypes.CppClassType ...containing the right options
child_attrs = ["base_type_node", "positional_args",
"keyword_args", "dtype_node"]
dtype_node = None
name = 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:
# Templated class
if self.keyword_args and self.keyword_args.key_value_pairs:
error(self.pos, "c++ templates cannot take keyword arguments");
self.type = PyrexTypes.error_type
else:
template_types = []
for template_node in self.positional_args:
type = template_node.analyse_as_type(env)
if type is None:
error(template_node.pos, "unknown type in template argument")
return error_type
template_types.append(type)
self.type = base_type.specialize_here(self.pos, template_types)
elif base_type.is_pyobject:
# Buffer
import Buffer
options = Buffer.analyse_buffer_options(
self.pos,
env,
self.positional_args,
self.keyword_args,
base_type.buffer_defaults)
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.iteritems() ])
self.type = PyrexTypes.BufferType(base_type, **options)
else:
# Array
empty_declarator = CNameDeclaratorNode(self.pos, name="", cname=None)
if len(self.positional_args) > 1 or self.keyword_args.key_value_pairs:
error(self.pos, "invalid array declaration")
self.type = PyrexTypes.error_type
else:
# It would be nice to merge this class with CArrayDeclaratorNode,
# but arrays are part of the declaration, not the type...
if not self.positional_args:
dimension = None
else:
dimension = self.positional_args[0]
self.array_declarator = CArrayDeclaratorNode(self.pos,
base = empty_declarator,
dimension = dimension)
self.type = self.array_declarator.analyse(base_type, env)[1]
return self.type
class CComplexBaseTypeNode(CBaseTypeNode):
# base_type CBaseTypeNode
# declarator CDeclaratorNode
child_attrs = ["base_type", "declarator"]
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 CVarDefNode(StatNode):
# C variable definition or forward/extern function declaration.
#
# visibility 'private' or 'public' or 'extern'
# base_type CBaseTypeNode
# declarators [CDeclaratorNode]
# in_pxd boolean
# api boolean
# properties [entry]
# decorators [cython.locals(...)] or None
# directive_locals { string : NameNode } locals defined by cython.locals(...)
child_attrs = ["base_type", "declarators"]
properties = ()
decorators = None
directive_locals = {}
def analyse_declarations(self, env, dest_scope = None):
if not dest_scope:
dest_scope = env
self.dest_scope = dest_scope
base_type = self.base_type.analyse(env)
# If the field is an external typedef, we cannot be sure about the type,
# so do conversion ourself rather than rely on the CPython mechanism (through
# a property; made in AnalyseDeclarationsTransform).
if (dest_scope.is_c_class_scope
and self.visibility in ('public', 'readonly')):
self.properties = []
need_property = True
else:
need_property = False
visibility = self.visibility
for declarator in self.declarators:
name_declarator, type = declarator.analyse(base_type, env)
if not type.is_complete():
if not (self.visibility == 'extern' and type.is_array):
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")
name = name_declarator.name
cname = name_declarator.cname
if name == '':
error(declarator.pos, "Missing name in declaration.")
return
if type.is_cfunction:
entry = dest_scope.declare_cfunction(name, type, declarator.pos,
cname = cname, visibility = self.visibility, in_pxd = self.in_pxd,
api = self.api)
if entry is not None:
entry.directive_locals = self.directive_locals
else:
if self.directive_locals:
s.error("Decorators can only be followed by functions")
if self.in_pxd and self.visibility != 'extern':
error(self.pos,
"Only 'extern' C variable declaration allowed in .pxd file")
entry = dest_scope.declare_var(name, type, declarator.pos,
cname = cname, visibility = visibility, is_cdef = 1)
if need_property:
self.properties.append(entry)
class CStructOrUnionDefNode(StatNode):
# name string
# cname string or None
# kind "struct" or "union"
# typedef_flag boolean
# visibility "public" or "private"
# in_pxd boolean
# attributes [CVarDefNode] or None
# entry Entry
# packed boolean
child_attrs = ["attributes"]
def analyse_declarations(self, env):
scope = None
if self.visibility == 'extern' and self.packed:
error(self.pos, "Cannot declare extern struct as 'packed'")
if self.attributes is not None:
scope = StructOrUnionScope(self.name)
self.entry = env.declare_struct_or_union(
self.name, self.kind, scope, self.typedef_flag, self.pos,
self.cname, visibility = self.visibility, packed = self.packed)
if self.attributes is not None:
if self.in_pxd and not env.in_cinclude:
self.entry.defined_in_pxd = 1
for attr in self.attributes:
attr.analyse_declarations(env, scope)
if self.visibility != 'extern':
need_typedef_indirection = False
for attr in scope.var_entries:
type = attr.type
while type.is_array:
type = type.base_type
if type == self.entry.type:
error(attr.pos, "Struct cannot contain itself as a member.")
if self.typedef_flag:
while type.is_ptr:
type = type.base_type
if type == self.entry.type:
need_typedef_indirection = True
if need_typedef_indirection:
# C can't handle typedef structs that refer to themselves.
struct_entry = self.entry
self.entry = env.declare_typedef(
self.name, struct_entry.type, self.pos,
cname = self.cname, visibility='ignore')
struct_entry.type.typedef_flag = False
# FIXME: this might be considered a hack ;-)
struct_entry.cname = struct_entry.type.cname = \
'_' + self.entry.type.typedef_cname
def analyse_expressions(self, env):
pass
def generate_execution_code(self, code):
pass
class CppClassNode(CStructOrUnionDefNode):
# name string
# cname string or None
# visibility "extern"
# in_pxd boolean
# attributes [CVarDefNode] or None
# entry Entry
# base_classes [string]
# templates [string] or None
def analyse_declarations(self, env):
scope = None
if self.attributes is not None:
scope = CppClassScope(self.name, env)
base_class_types = []
for base_class_name in self.base_classes:
base_class_entry = env.lookup(base_class_name)
if base_class_entry is None:
error(self.pos, "'%s' not found" % base_class_name)
elif not base_class_entry.is_type or not base_class_entry.type.is_cpp_class:
error(self.pos, "'%s' is not a cpp class type" % base_class_name)
else:
base_class_types.append(base_class_entry.type)
if self.templates is None:
template_types = None
else:
template_types = [PyrexTypes.TemplatePlaceholderType(template_name) for template_name in self.templates]
self.entry = env.declare_cpp_class(
self.name, scope, self.pos,
self.cname, base_class_types, visibility = self.visibility, templates = template_types)
self.entry.is_cpp_class = 1
if self.attributes is not None:
if self.in_pxd and not env.in_cinclude:
self.entry.defined_in_pxd = 1
for attr in self.attributes:
attr.analyse_declarations(scope)
class CEnumDefNode(StatNode):
# name string or None
# cname string or None
# items [CEnumDefItemNode]
# typedef_flag boolean
# visibility "public" or "private"
# in_pxd boolean
# entry Entry
child_attrs = ["items"]
def analyse_declarations(self, env):
self.entry = env.declare_enum(self.name, self.pos,
cname = self.cname, typedef_flag = self.typedef_flag,
visibility = self.visibility)
if self.items is not None:
if self.in_pxd and not env.in_cinclude:
self.entry.defined_in_pxd = 1
for item in self.items:
item.analyse_declarations(env, self.entry)
def analyse_expressions(self, env):
pass
def generate_execution_code(self, code):
if self.visibility == 'public':
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)))
code.put_gotref(temp)
code.putln('if (__Pyx_SetAttrString(%s, "%s", %s) < 0) %s' % (
Naming.module_cname,
item.name,
temp,
code.error_goto(item.pos)))
code.put_decref_clear(temp, PyrexTypes.py_object_type)
code.funcstate.release_temp(temp)
class CEnumDefItemNode(StatNode):
# name string
# cname string or None
# value ExprNode or None
child_attrs = ["value"]
def analyse_declarations(self, env, enum_entry):
if self.value:
self.value.analyse_const_expression(env)
if not self.value.type.is_int:
self.value = self.value.coerce_to(PyrexTypes.c_int_type, env)
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)
enum_entry.enum_values.append(entry)
class CTypeDefNode(StatNode):
# base_type CBaseTypeNode
# declarator CDeclaratorNode
# visibility "public" or "private"
# in_pxd boolean
child_attrs = ["base_type", "declarator"]
def analyse_declarations(self, env):
base = self.base_type.analyse(env)
name_declarator, type = self.declarator.analyse(base, env)
name = name_declarator.name
cname = name_declarator.cname
entry = env.declare_typedef(name, type, self.pos,
cname = cname, visibility = self.visibility)
if self.in_pxd and not env.in_cinclude:
entry.defined_in_pxd = 1
def analyse_expressions(self, env):
pass
def generate_execution_code(self, code):
pass
class FuncDefNode(StatNode, BlockNode):
# Base class for function definition nodes.
#
# return_type PyrexType
# #filename string C name of filename string const
# entry Symtab.Entry
# needs_closure boolean Whether or not this function has inner functions/classes/yield
# directive_locals { string : NameNode } locals defined by cython.locals(...)
py_func = None
assmt = None
needs_closure = False
modifiers = []
def analyse_default_values(self, env):
genv = env.global_scope()
default_seen = 0
for arg in self.args:
if arg.default:
default_seen = 1
if arg.is_generic:
arg.default.analyse_types(env)
arg.default = arg.default.coerce_to(arg.type, genv)
else:
error(arg.pos,
"This argument cannot have a default value")
arg.default = None
elif arg.kw_only:
default_seen = 1
elif default_seen:
error(arg.pos, "Non-default argument following default argument")
def need_gil_acquisition(self, lenv):
return 0
def create_local_scope(self, env):
genv = env
while genv.is_py_class_scope or genv.is_c_class_scope:
genv = env.outer_scope
if self.needs_closure:
lenv = ClosureScope(name=self.entry.name,
outer_scope = genv,
scope_name=self.entry.cname)
else:
lenv = LocalScope(name=self.entry.name,
outer_scope=genv,
parent_scope=env)
lenv.return_type = self.return_type
type = self.entry.type
if type.is_cfunction:
lenv.nogil = type.nogil and not type.with_gil
self.local_scope = lenv
lenv.directives = env.directives
return lenv
def generate_function_definitions(self, env, code):
import Buffer
lenv = self.local_scope
if lenv.is_closure_scope:
outer_scope_cname = "%s->%s" % (Naming.cur_scope_cname,
Naming.outer_scope_cname)
else:
outer_scope_cname = Naming.outer_scope_cname
lenv.mangle_closure_cnames(outer_scope_cname)
# Generate closure function definitions
self.body.generate_function_definitions(lenv, code)
# generate lambda function definitions
for node in lenv.lambda_defs:
node.generate_function_definitions(lenv, code)
is_getbuffer_slot = (self.entry.name == "__getbuffer__" and
self.entry.scope.is_c_class_scope)
is_releasebuffer_slot = (self.entry.name == "__releasebuffer__" and
self.entry.scope.is_c_class_scope)
is_buffer_slot = is_getbuffer_slot or is_releasebuffer_slot
if is_buffer_slot:
if 'cython_unused' not in self.modifiers:
self.modifiers = self.modifiers + ['cython_unused']
preprocessor_guard = None
if self.entry.is_special and not is_buffer_slot:
slot = TypeSlots.method_name_to_slot.get(self.entry.name)
if slot:
preprocessor_guard = slot.preprocessor_guard_code()
if (self.entry.name == '__long__' and
not self.entry.scope.lookup_here('__int__')):
preprocessor_guard = None
profile = code.globalstate.directives['profile']
if profile:
if lenv.nogil:
error(self.pos, "Cannot profile nogil function.")
code.globalstate.use_utility_code(profile_utility_code)
# Generate C code for header and body of function
code.enter_cfunc_scope()
code.return_from_error_cleanup_label = code.new_label()
# ----- Top-level constants used by this function
code.mark_pos(self.pos)
self.generate_cached_builtins_decls(lenv, code)
# ----- Function header
code.putln("")
if preprocessor_guard:
code.putln(preprocessor_guard)
with_pymethdef = self.needs_assignment_synthesis(env, code)
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)
# ----- Local variable declarations
if lenv.is_closure_scope:
code.put(lenv.scope_class.type.declaration_code(Naming.cur_scope_cname))
code.putln(";")
elif env.is_closure_scope:
code.put(env.scope_class.type.declaration_code(Naming.outer_scope_cname))
code.putln(";")
self.generate_argument_declarations(lenv, code)
for entry in lenv.var_entries:
if not entry.in_closure:
code.put_var_declaration(entry)
init = ""
if not self.return_type.is_void:
if self.return_type.is_pyobject:
init = " = NULL"
code.putln(
"%s%s;" %
(self.return_type.declaration_code(Naming.retval_cname),
init))
tempvardecl_code = code.insertion_point()
self.generate_keyword_list(code)
if profile:
code.put_trace_declarations()
# ----- Extern library function declarations
lenv.generate_library_function_declarations(code)
# ----- GIL acquisition
acquire_gil = self.acquire_gil
if acquire_gil:
env.use_utility_code(force_init_threads_utility_code)
code.putln("PyGILState_STATE _save = PyGILState_Ensure();")
# ----- set up refnanny
if not lenv.nogil:
code.put_setup_refcount_context(self.entry.name)
# ----- Automatic lead-ins for certain special functions
if is_getbuffer_slot:
self.getbuffer_init(code)
# ----- Create closure scope object
if self.needs_closure:
code.putln("%s = (%s)%s->tp_new(%s, %s, NULL);" % (
Naming.cur_scope_cname,
lenv.scope_class.type.declaration_code(''),
lenv.scope_class.type.typeptr_cname,
lenv.scope_class.type.typeptr_cname,
Naming.empty_tuple))
code.putln("if (unlikely(!%s)) {" % Naming.cur_scope_cname)
if is_getbuffer_slot:
self.getbuffer_error_cleanup(code)
if not lenv.nogil:
code.put_finish_refcount_context()
# FIXME: what if the error return value is a Python value?
code.putln("return %s;" % self.error_value())
code.putln("}")
code.put_gotref(Naming.cur_scope_cname)
# Note that it is unsafe to decref the scope at this point.
if env.is_closure_scope:
code.putln("%s = (%s)%s;" % (
outer_scope_cname,
env.scope_class.type.declaration_code(''),
Naming.self_cname))
if self.needs_closure:
# inner closures own a reference to their outer parent
code.put_incref(outer_scope_cname, env.scope_class.type)
code.put_giveref(outer_scope_cname)
# ----- Trace function call
if profile:
# this looks a bit late, but if we don't get here due to a
# fatal error before hand, it's not really worth tracing
code.put_trace_call(self.entry.name, self.pos)
# ----- Fetch arguments
self.generate_argument_parsing_code(env, code)
# If an argument is assigned to in the body, we must
# incref it to properly keep track of refcounts.
for entry in lenv.arg_entries:
if entry.type.is_pyobject:
if entry.assignments and not entry.in_closure:
code.put_var_incref(entry)
# ----- Initialise local variables
for entry in lenv.var_entries:
if entry.type.is_pyobject and entry.init_to_none and entry.used:
code.put_init_var_to_py_none(entry)
# ----- Initialise local buffer auxiliary variables
for entry in lenv.var_entries + lenv.arg_entries:
if entry.type.is_buffer and entry.buffer_aux.buffer_info_var.used:
code.putln("%s.buf = NULL;" %
entry.buffer_aux.buffer_info_var.cname)
# ----- Check and convert arguments
self.generate_argument_type_tests(code)
# ----- Acquire buffer arguments
for entry in lenv.arg_entries:
if entry.type.is_buffer:
Buffer.put_acquire_arg_buffer(entry, code, self.pos)
# -------------------------
# ----- Function body -----
# -------------------------
self.body.generate_execution_code(code)
# ----- Default return value
code.putln("")
if self.return_type.is_pyobject:
#if self.return_type.is_extension_type:
# lhs = "(PyObject *)%s" % Naming.retval_cname
#else:
lhs = Naming.retval_cname
code.put_init_to_py_none(lhs, self.return_type)
else:
val = self.return_type.default_value
if val:
code.putln("%s = %s;" % (Naming.retval_cname, val))
# ----- Error cleanup
if code.error_label in code.labels_used:
code.put_goto(code.return_label)
code.put_label(code.error_label)
for cname, type in code.funcstate.all_managed_temps():
code.put_xdecref(cname, type)
# Clean up buffers -- this calls a Python function
# so need to save and restore error state
buffers_present = len(lenv.buffer_entries) > 0
if buffers_present:
code.globalstate.use_utility_code(restore_exception_utility_code)
code.putln("{ PyObject *__pyx_type, *__pyx_value, *__pyx_tb;")
code.putln("__Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb);")
for entry in lenv.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);}")
err_val = self.error_value()
exc_check = self.caller_will_check_exceptions()
if err_val is not None or exc_check:
# TODO: Fix exception tracing (though currently unused by cProfile).
# code.globalstate.use_utility_code(get_exception_tuple_utility_code)
# code.put_trace_exception()
code.putln('__Pyx_AddTraceback("%s");' % self.entry.qualified_name)
else:
warning(self.entry.pos, "Unraisable exception in function '%s'." \
% self.entry.qualified_name, 0)
code.putln(
'__Pyx_WriteUnraisable("%s");' %
self.entry.qualified_name)
env.use_utility_code(unraisable_exception_utility_code)
env.use_utility_code(restore_exception_utility_code)
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:
code.putln("%s = %s;" % (Naming.retval_cname, err_val))
if is_getbuffer_slot:
self.getbuffer_error_cleanup(code)
# If we are using the non-error cleanup section we should
# jump past it if we have an error. The if-test below determine
# whether this section is used.
if buffers_present or is_getbuffer_slot:
code.put_goto(code.return_from_error_cleanup_label)
# ----- Non-error return cleanup
code.put_label(code.return_label)
for entry in lenv.buffer_entries:
if entry.used:
Buffer.put_release_buffer_code(code, entry)
if is_getbuffer_slot:
self.getbuffer_normal_cleanup(code)
# ----- Return cleanup for both error and no-error return
code.put_label(code.return_from_error_cleanup_label)
if not Options.init_local_none:
for entry in lenv.var_entries:
if lenv.control_flow.get_state((entry.name, 'initialized')) is not True:
entry.xdecref_cleanup = 1
for entry in lenv.var_entries:
if entry.type.is_pyobject:
if entry.used and not entry.in_closure:
code.put_var_decref(entry)
elif entry.in_closure and self.needs_closure:
code.put_giveref(entry.cname)
# Decref any increfed args
for entry in lenv.arg_entries:
if entry.type.is_pyobject:
if entry.in_closure:
code.put_var_giveref(entry)
elif entry.assignments:
code.put_var_decref(entry)
if self.needs_closure:
code.put_decref(Naming.cur_scope_cname, lenv.scope_class.type)
# ----- Return
# This code is duplicated in ModuleNode.generate_module_init_func
if not lenv.nogil:
default_retval = self.return_type.default_value
err_val = self.error_value()
if err_val is None and default_retval:
err_val = default_retval
if self.return_type.is_pyobject:
code.put_xgiveref(self.return_type.as_pyobject(Naming.retval_cname))
if self.entry.is_special and self.entry.name == "__hash__":
# 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))
if profile:
if self.return_type.is_pyobject:
code.put_trace_return(Naming.retval_cname)
else:
code.put_trace_return("Py_None")
if not lenv.nogil:
code.put_finish_refcount_context()
if acquire_gil:
code.putln("PyGILState_Release(_save);")
if not self.return_type.is_void:
code.putln("return %s;" % Naming.retval_cname)
code.putln("}")
if preprocessor_guard:
code.putln("#endif /*!(%s)*/" % preprocessor_guard)
# ----- Go back and insert temp variable declarations
tempvardecl_code.put_temp_declarations(code.funcstate)
# ----- Python version
code.exit_cfunc_scope()
if self.py_func:
self.py_func.generate_function_definitions(env, code)
self.generate_wrapper_functions(code)
def declare_argument(self, env, arg):
if arg.type.is_void:
error(arg.pos, "Invalid use of 'void'")
elif not arg.type.is_complete() and not arg.type.is_array:
error(arg.pos,
"Argument type '%s' is incomplete" % arg.type)
return env.declare_arg(arg.name, arg.type, arg.pos)
def generate_arg_type_test(self, arg, code):
# Generate type test for one argument.
if arg.type.typeobj_is_available():
code.globalstate.use_utility_code(arg_type_test_utility_code)
typeptr_cname = arg.type.typeptr_cname
arg_code = "((PyObject *)%s)" % arg.entry.cname
code.putln(
'if (unlikely(!__Pyx_ArgTypeTest(%s, %s, %d, "%s", %s))) %s' % (
arg_code,
typeptr_cname,
arg.accept_none,
arg.name,
arg.type.is_builtin_type,
code.error_goto(arg.pos)))
else:
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.
code.globalstate.use_utility_code(arg_type_test_utility_code)
code.putln('if (unlikely(((PyObject *)%s) == Py_None)) {' % arg.entry.cname)
code.putln('''PyErr_Format(PyExc_TypeError, "Argument '%s' must not be None"); %s''' % (
arg.name,
code.error_goto(arg.pos)))
code.putln('}')
def generate_wrapper_functions(self, code):
pass
def generate_execution_code(self, code):
# Evaluate and store argument default values
for arg in self.args:
default = arg.default
if default:
if not default.is_literal:
default.generate_evaluation_code(code)
default.make_owned_reference(code)
result = default.result_as(arg.type)
code.putln(
"%s = %s;" % (
arg.calculate_default_value_code(code),
result))
if arg.type.is_pyobject:
code.put_giveref(default.result())
default.generate_post_assignment_code(code)
default.free_temps(code)
# For Python class methods, create and store function object
if self.assmt:
self.assmt.generate_execution_code(code)
#
# Special code for the __getbuffer__ function
#
def getbuffer_init(self, code):
info = self.local_scope.arg_entries[1].cname
# Python 3.0 betas have a bug in memoryview which makes it call
# getbuffer with a NULL parameter. For now we work around this;
# the following line should be removed when this bug is fixed.
code.putln("if (%s == NULL) return 0;" % info)
code.putln("%s->obj = Py_None; __Pyx_INCREF(Py_None);" % info)
code.put_giveref("%s->obj" % info) # Do not refnanny object within structs
def getbuffer_error_cleanup(self, code):
info = self.local_scope.arg_entries[1].cname
code.put_gotref("%s->obj" % info)
code.putln("__Pyx_DECREF(%s->obj); %s->obj = NULL;" %
(info, info))
def getbuffer_normal_cleanup(self, code):
info = self.local_scope.arg_entries[1].cname
code.putln("if (%s->obj == Py_None) {" % info)
code.put_gotref("Py_None")
code.putln("__Pyx_DECREF(Py_None); %s->obj = NULL;" % info)
code.putln("}")
class CFuncDefNode(FuncDefNode):
# C function definition.
#
# modifiers ['inline']
# visibility 'private' or 'public' or 'extern'
# base_type CBaseTypeNode
# declarator CDeclaratorNode
# body StatListNode
# api boolean
# decorators [DecoratorNode] list of decorators
#
# with_gil boolean Acquire GIL around body
# type CFuncType
# py_func wrapper for calling from Python
# overridable whether or not this is a cpdef function
# inline_in_pxd whether this is an inline function in a pxd file
child_attrs = ["base_type", "declarator", "body", "py_func"]
inline_in_pxd = False
decorators = None
directive_locals = {}
def unqualified_name(self):
return self.entry.name
def analyse_declarations(self, env):
self.directive_locals.update(env.directives['locals'])
base_type = self.base_type.analyse(env)
# The 2 here is because we need both function and argument names.
name_declarator, type = self.declarator.analyse(base_type, env, nonempty = 2 * (self.body is not None))
if not type.is_cfunction:
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
# from the base type of an extension type.
self.type = type
type.is_overridable = self.overridable
declarator = self.declarator
while not hasattr(declarator, 'args'):
declarator = declarator.base
self.args = declarator.args
for formal_arg, type_arg in zip(self.args, type.args):
formal_arg.type = type_arg.type
formal_arg.name = type_arg.name
formal_arg.cname = type_arg.cname
name = name_declarator.name
cname = name_declarator.cname
self.entry = env.declare_cfunction(
name, type, self.pos,
cname = cname, visibility = self.visibility,
defining = self.body is not None,
api = self.api, modifiers = self.modifiers)
self.entry.inline_func_in_pxd = self.inline_in_pxd
self.return_type = type.return_type
if self.overridable and not env.is_module_scope:
if len(self.args) < 1 or not self.args[0].type.is_pyobject:
# An error will be produced in the cdef function
self.overridable = False
if self.overridable:
import ExprNodes
py_func_body = self.call_self_node(is_module_scope = env.is_module_scope)
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,
is_wrapper = 1)
self.py_func.is_module_scope = env.is_module_scope
self.py_func.analyse_declarations(env)
self.entry.as_variable = self.py_func.entry
# Reset scope entry the above cfunction
env.entries[name] = self.entry
if 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])
self.create_local_scope(env)
def call_self_node(self, omit_optional_args=0, is_module_scope=0):
import ExprNodes
args = self.type.args
if omit_optional_args:
args = args[:len(args) - self.type.optional_arg_count]
arg_names = [arg.name for arg in args]
if is_module_scope:
cfunc = ExprNodes.NameNode(self.pos, name=self.entry.name)
else:
self_arg = ExprNodes.NameNode(self.pos, name=arg_names[0])
cfunc = ExprNodes.AttributeNode(self.pos, obj=self_arg, attribute=self.entry.name)
skip_dispatch = not is_module_scope or Options.lookup_module_cpdef
c_call = ExprNodes.SimpleCallNode(self.pos, function=cfunc, args=[ExprNodes.NameNode(self.pos, name=n) for n in arg_names[1-is_module_scope:]], wrapper_call=skip_dispatch)
return ReturnStatNode(pos=self.pos, return_type=PyrexTypes.py_object_type, value=c_call)
def declare_arguments(self, env):
for arg in self.type.args:
if not arg.name:
error(arg.pos, "Missing argument name")
self.declare_argument(env, arg)
def need_gil_acquisition(self, lenv):
return self.type.with_gil
def nogil_check(self, env):
type = self.type
with_gil = type.with_gil
if type.nogil and not with_gil:
if type.return_type.is_pyobject:
error(self.pos,
"Function with Python return type cannot be declared nogil")
for entry in self.local_scope.var_entries:
if entry.type.is_pyobject:
error(self.pos, "Function declared nogil has Python locals or temporaries")
def analyse_expressions(self, env):
self.local_scope.directives = env.directives
if self.py_func is not None:
# this will also analyse the default values
self.py_func.analyse_expressions(env)
else:
self.analyse_default_values(env)
self.acquire_gil = self.need_gil_acquisition(self.local_scope)
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):
arg_decls = []
type = self.type
visibility = self.entry.visibility
for arg in type.args[:len(type.args)-type.optional_arg_count]:
arg_decls.append(arg.declaration_code())
if with_dispatch and self.overridable:
arg_decls.append(PyrexTypes.c_int_type.declaration_code(Naming.skip_dispatch_cname))
if type.optional_arg_count and with_opt_args:
arg_decls.append(type.op_arg_struct.declaration_code(Naming.optional_args_cname))
if type.has_varargs:
arg_decls.append("...")
if not arg_decls:
arg_decls = ["void"]
if cname is None:
cname = self.entry.func_cname
entity = type.function_header_code(cname, ', '.join(arg_decls))
if visibility == 'public':
dll_linkage = "DL_EXPORT"
else:
dll_linkage = None
header = self.return_type.declaration_code(entity,
dll_linkage = dll_linkage)
if visibility == 'extern':
storage_class = "%s " % Naming.extern_c_macro
elif visibility == 'public':
storage_class = ""
else:
storage_class = "static "
if 'inline' in self.modifiers:
self.modifiers[self.modifiers.index('inline')] = 'cython_inline'
code.putln("%s%s %s {" % (
storage_class,
' '.join(self.modifiers).upper(), # macro forms
header))
def generate_argument_declarations(self, env, code):
for arg in self.args:
if arg.default:
result = arg.calculate_default_value_code(code)
code.putln('%s = %s;' % (
arg.type.declaration_code(arg.cname), result))
def generate_keyword_list(self, code):
pass
def generate_argument_parsing_code(self, env, code):
i = 0
if self.type.optional_arg_count:
code.putln('if (%s) {' % Naming.optional_args_cname)
for arg in self.args:
if arg.default:
code.putln('if (%s->%sn > %s) {' % (Naming.optional_args_cname, Naming.pyrex_prefix, i))
declarator = arg.declarator
while not hasattr(declarator, 'name'):
declarator = declarator.base
code.putln('%s = %s->%s;' % (arg.cname, Naming.optional_args_cname, self.type.opt_arg_cname(declarator.name)))
i += 1
for _ in range(self.type.optional_arg_count):
code.putln('}')
code.putln('}')
def generate_argument_conversion_code(self, code):
pass
def generate_argument_type_tests(self, code):
# Generate type tests for args whose type in a parent
# class is a supertype of the declared type.
for arg in self.type.args:
if arg.needs_type_test:
self.generate_arg_type_test(arg, code)
elif arg.type.is_pyobject and not arg.accept_none:
self.generate_arg_none_check(arg, code)
def error_value(self):
if self.return_type.is_pyobject:
return "0"
else:
#return None
return self.entry.type.exception_value
def caller_will_check_exceptions(self):
return self.entry.type.exception_check
def generate_wrapper_functions(self, code):
# If the C signature of a function has changed, we need to generate
# wrappers to put in the slots here.
k = 0
entry = self.entry
func_type = entry.type
while entry.prev_entry is not None:
k += 1
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)
if not self.return_type.is_void:
code.put('return ')
args = self.type.args
arglist = [arg.cname for arg in args[:len(args)-self.type.optional_arg_count]]
if entry.type.is_overridable:
arglist.append(Naming.skip_dispatch_cname)
elif func_type.is_overridable:
arglist.append('0')
if entry.type.optional_arg_count:
arglist.append(Naming.optional_args_cname)
elif func_type.optional_arg_count:
arglist.append('NULL')
code.putln('%s(%s);' % (self.entry.func_cname, ', '.join(arglist)))
code.putln('}')
class PyArgDeclNode(Node):
# Argument which must be a Python object (used
# for * and ** arguments).
#
# name string
# entry Symtab.Entry
# annotation ExprNode or None Py3 argument annotation
child_attrs = []
def generate_function_definitions(self, env, code):
self.entry.generate_function_definitions(env, code)
class DecoratorNode(Node):
# A decorator
#
# decorator NameNode or CallNode or AttributeNode
child_attrs = ['decorator']
class DefNode(FuncDefNode):
# A Python function definition.
#
# name string the Python name of the function
# lambda_name string the internal name of a lambda 'function'
# decorators [DecoratorNode] list of decorators
# args [CArgDeclNode] formal arguments
# star_arg PyArgDeclNode or None * argument
# starstar_arg PyArgDeclNode or None ** argument
# doc EncodedString or None
# body StatListNode
# return_type_annotation
# ExprNode or None the Py3 return type annotation
#
# The following subnode is constructed internally
# when the def statement is inside a Python class definition.
#
# assmt AssignmentNode Function construction/assignment
child_attrs = ["args", "star_arg", "starstar_arg", "body", "decorators"]
lambda_name = None
assmt = None
num_kwonly_args = 0
num_required_kw_args = 0
reqd_kw_flags_cname = "0"
is_wrapper = 0
decorators = None
return_type_annotation = None
entry = None
acquire_gil = 0
self_in_stararg = 0
def __init__(self, pos, **kwds):
FuncDefNode.__init__(self, pos, **kwds)
k = rk = r = 0
for arg in self.args:
if arg.kw_only:
k += 1
if not arg.default:
rk += 1
if not arg.default:
r += 1
self.num_kwonly_args = k
self.num_required_kw_args = rk
self.num_required_args = r
def as_cfunction(self, cfunc=None, scope=None):
if self.star_arg:
error(self.star_arg.pos, "cdef function cannot have star argument")
if self.starstar_arg:
error(self.starstar_arg.pos, "cdef function cannot have starstar argument")
if cfunc is None:
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,
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 = False,
nogil = False,
with_gil = False,
is_overridable = True)
cfunc = CVarDefNode(self.pos, type=cfunc_type)
else:
cfunc_type = cfunc.type
if len(self.args) != len(cfunc_type.args) or cfunc_type.has_varargs:
error(self.pos, "wrong number of arguments")
error(cfunc.pos, "previous declaration here")
for formal_arg, type_arg in zip(self.args, cfunc_type.args):
name_declarator, type = formal_arg.analyse(cfunc.scope, nonempty=1)
if type is None or type is PyrexTypes.py_object_type or formal_arg.is_self:
formal_arg.type = type_arg.type
formal_arg.name_declarator = name_declarator
import ExprNodes
if cfunc_type.exception_value is None:
exception_value = None
else:
exception_value = ExprNodes.ConstNode(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)
return CFuncDefNode(self.pos,
modifiers = [],
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', {}))
def analyse_declarations(self, env):
self.is_classmethod = self.is_staticmethod = False
if self.decorators:
for decorator in self.decorators:
func = decorator.decorator
if func.is_name:
self.is_classmethod |= func.name == 'classmethod'
self.is_staticmethod |= func.name == 'staticmethod'
if self.is_classmethod and env.lookup_here('classmethod'):
# classmethod() was overridden - not much we can do here ...
self.is_classmethod = False
if self.is_staticmethod and env.lookup_here('staticmethod'):
# staticmethod() was overridden - not much we can do here ...
self.is_staticmethod = False
self.analyse_argument_types(env)
if self.name == '':
self.declare_lambda_function(env)
else:
self.declare_pyfunction(env)
self.analyse_signature(env)
self.return_type = self.entry.signature.return_type()
self.create_local_scope(env)
def analyse_argument_types(self, env):
directive_locals = self.directive_locals = env.directives['locals']
allow_none_for_extension_args = env.directives['allow_none_for_extension_args']
for arg in self.args:
if hasattr(arg, 'name'):
type = arg.type
name_declarator = None
else:
base_type = arg.base_type.analyse(env)
name_declarator, type = \
arg.declarator.analyse(base_type, env)
arg.name = name_declarator.name
if arg.name in directive_locals:
type_node = directive_locals[arg.name]
other_type = type_node.analyse_as_type(env)
if other_type is None:
error(type_node.pos, "Not a type")
elif (type is not PyrexTypes.py_object_type
and not 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:
type = other_type
if name_declarator and name_declarator.cname:
error(self.pos,
"Python function argument cannot have C name specification")
arg.type = type.as_argument_type()
arg.hdr_type = None
arg.needs_conversion = 0
arg.needs_type_test = 0
arg.is_generic = 1
if arg.type.is_pyobject:
if arg.or_none:
arg.accept_none = True
elif arg.not_none:
arg.accept_none = False
elif arg.type.is_extension_type or arg.type.is_builtin_type:
if arg.default and arg.default.constant_result is None:
# special case: def func(MyType obj = None)
arg.accept_none = True
else:
# default depends on compiler directive
arg.accept_none = allow_none_for_extension_args
else:
# probably just a plain 'object'
arg.accept_none = True
else:
arg.accept_none = True # won't be used, but must be there
if arg.not_none:
error(arg.pos, "Only Python type arguments can have 'not None'")
if arg.or_none:
error(arg.pos, "Only Python type arguments can have 'or None'")
def analyse_signature(self, env):
if self.entry.is_special:
self.entry.trivial_signature = len(self.args) == 1 and not (self.star_arg or self.starstar_arg)
elif not env.directives['always_allow_keywords'] and not (self.star_arg or self.starstar_arg):
# Use the simpler calling signature for zero- and one-argument functions.
if self.entry.signature is TypeSlots.pyfunction_signature:
if len(self.args) == 0:
self.entry.signature = TypeSlots.pyfunction_noargs
elif len(self.args) == 1:
if self.args[0].default is None and not self.args[0].kw_only:
self.entry.signature = TypeSlots.pyfunction_onearg
elif self.entry.signature is TypeSlots.pymethod_signature:
if len(self.args) == 1:
self.entry.signature = TypeSlots.unaryfunc
elif len(self.args) == 2:
if self.args[1].default is None and not self.args[1].kw_only:
self.entry.signature = TypeSlots.ibinaryfunc
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:
# 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)
sig = self.entry.signature = TypeSlots.pyfunction_signature # self is not 'really' used
self.self_in_stararg = 1
nfixed = 0
for i in range(min(nfixed, len(self.args))):
arg = self.args[i]
arg.is_generic = 0
if sig.is_self_arg(i) and not self.is_staticmethod:
if self.is_classmethod:
arg.is_type_arg = 1
arg.hdr_type = arg.type = Builtin.type_type
else:
arg.is_self_arg = 1
arg.hdr_type = arg.type = env.parent_type
arg.needs_conversion = 0
else:
arg.hdr_type = sig.fixed_arg_type(i)
if not arg.type.same_as(arg.hdr_type):
if arg.hdr_type.is_pyobject and arg.type.is_pyobject:
arg.needs_type_test = 1
else:
arg.needs_conversion = 1
if arg.needs_conversion:
arg.hdr_cname = Naming.arg_prefix + arg.name
else:
arg.hdr_cname = Naming.var_prefix + arg.name
if nfixed > len(self.args):
self.bad_signature()
return
elif nfixed < len(self.args):
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):
arg.needs_type_test = 1
def bad_signature(self):
sig = self.entry.signature
expected_str = "%d" % sig.num_fixed_args()
if sig.has_generic_args:
expected_str = expected_str + " or more"
name = self.name
if name.startswith("__") and name.endswith("__"):
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))
def signature_has_nongeneric_args(self):
argcount = len(self.args)
if argcount == 0 or (
argcount == 1 and (self.args[0].is_self_arg or
self.args[0].is_type_arg)):
return 0
return 1
def signature_has_generic_args(self):
return self.entry.signature.has_generic_args
def declare_pyfunction(self, env):
#print "DefNode.declare_pyfunction:", self.name, "in", env ###
name = self.name
entry = env.lookup_here(name)
if entry and entry.type.is_cfunction and not self.is_wrapper:
warning(self.pos, "Overriding cdef method with def method.", 5)
entry = env.declare_pyfunction(name, self.pos)
self.entry = entry
prefix = env.scope_prefix
entry.func_cname = \
Naming.pyfunc_prefix + prefix + name
entry.pymethdef_cname = \
Naming.pymethdef_prefix + prefix + name
if Options.docstrings:
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:
entry.wrapperbase_cname = None
else:
entry.wrapperbase_cname = Naming.wrapperbase_prefix + prefix + name
else:
entry.doc = None
def declare_lambda_function(self, env):
name = self.name
prefix = env.scope_prefix
func_cname = \
Naming.lambda_func_prefix + u'funcdef' + prefix + self.lambda_name
entry = env.declare_lambda_function(func_cname, self.pos)
entry.pymethdef_cname = \
Naming.lambda_func_prefix + u'methdef' + prefix + self.lambda_name
entry.qualified_name = env.qualify_name(self.lambda_name)
entry.doc = None
self.entry = entry
def declare_arguments(self, env):
for arg in self.args:
if not arg.name:
error(arg.pos, "Missing argument name")
else:
env.control_flow.set_state((), (arg.name, 'source'), 'arg')
env.control_flow.set_state((), (arg.name, 'initialized'), True)
if arg.needs_conversion:
arg.entry = env.declare_var(arg.name, arg.type, arg.pos)
if arg.type.is_pyobject:
arg.entry.init = "0"
arg.entry.init_to_none = 0
else:
arg.entry = self.declare_argument(env, arg)
arg.entry.used = 1
arg.entry.is_self_arg = arg.is_self_arg
if arg.hdr_type:
if arg.is_self_arg or arg.is_type_arg or \
(arg.type.is_extension_type and not arg.hdr_type.is_extension_type):
arg.entry.is_declared_generic = 1
self.declare_python_arg(env, self.star_arg)
self.declare_python_arg(env, self.starstar_arg)
def declare_python_arg(self, env, arg):
if arg:
if env.directives['infer_types'] != False:
type = PyrexTypes.unspecified_type
else:
type = py_object_type
entry = env.declare_var(arg.name, type, arg.pos)
entry.used = 1
entry.init = "0"
entry.init_to_none = 0
entry.xdecref_cleanup = 1
arg.entry = entry
env.control_flow.set_state((), (arg.name, 'initialized'), True)
def analyse_expressions(self, env):
self.local_scope.directives = env.directives
self.analyse_default_values(env)
if self.needs_assignment_synthesis(env):
# Shouldn't we be doing this at the module level too?
self.synthesize_assignment_node(env)
def needs_assignment_synthesis(self, env, code=None):
# Should enable for module level as well, that will require more testing...
if env.is_module_scope:
if code is None:
return env.directives['binding']
else:
return code.globalstate.directives['binding']
return env.is_py_class_scope or env.is_closure_scope
def synthesize_assignment_node(self, env):
import ExprNodes
if env.is_py_class_scope:
rhs = ExprNodes.UnboundMethodNode(self.pos,
function = ExprNodes.PyCFunctionNode(self.pos,
pymethdef_cname = self.entry.pymethdef_cname))
elif env.is_closure_scope:
rhs = ExprNodes.InnerFunctionNode(
self.pos, pymethdef_cname = self.entry.pymethdef_cname)
else:
rhs = ExprNodes.PyCFunctionNode(
self.pos, pymethdef_cname = self.entry.pymethdef_cname, binding = env.directives['binding'])
self.assmt = SingleAssignmentNode(self.pos,
lhs = ExprNodes.NameNode(self.pos, name = self.name),
rhs = rhs)
self.assmt.analyse_declarations(env)
self.assmt.analyse_expressions(env)
def generate_function_header(self, code, with_pymethdef, proto_only=0):
arg_code_list = []
sig = self.entry.signature
if sig.has_dummy_arg or self.self_in_stararg:
arg_code_list.append(
"PyObject *%s" % Naming.self_cname)
for arg in self.args:
if not arg.is_generic:
if arg.is_self_arg or arg.is_type_arg:
arg_code_list.append("PyObject *%s" % arg.hdr_cname)
else:
arg_code_list.append(
arg.hdr_type.declaration_code(arg.hdr_cname))
if not self.entry.is_special and sig.method_flags() == [TypeSlots.method_noargs]:
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))
arg_code = ", ".join(arg_code_list)
dc = self.return_type.declaration_code(self.entry.func_cname)
mf = " ".join(self.modifiers).upper()
if mf: mf += " "
header = "static %s%s(%s)" % (mf, dc, arg_code)
code.putln("%s; /*proto*/" % header)
if proto_only:
return
if (Options.docstrings and self.entry.doc and
not self.entry.scope.is_property_scope and
(not self.entry.is_special or self.entry.wrapperbase_cname)):
docstr = self.entry.doc
if docstr.is_unicode:
docstr = docstr.utf8encode()
code.putln(
'static char %s[] = "%s";' % (
self.entry.doc_cname,
split_string_literal(escape_byte_string(docstr))))
if self.entry.is_special:
code.putln(
"struct wrapperbase %s;" % self.entry.wrapperbase_cname)
if with_pymethdef:
code.put(
"static PyMethodDef %s = " %
self.entry.pymethdef_cname)
code.put_pymethoddef(self.entry, ";", allow_skip=False)
code.putln("%s {" % header)
def generate_argument_declarations(self, env, code):
for arg in self.args:
if arg.is_generic: # or arg.needs_conversion:
if arg.needs_conversion:
code.putln("PyObject *%s = 0;" % arg.hdr_cname)
elif not arg.entry.in_closure:
code.put_var_declaration(arg.entry)
def generate_keyword_list(self, code):
if self.signature_has_generic_args() and \
self.signature_has_nongeneric_args():
code.put(
"static PyObject **%s[] = {" %
Naming.pykwdlist_cname)
for arg in self.args:
if arg.is_generic:
pystring_cname = code.intern_identifier(arg.name)
code.put('&%s,' % pystring_cname)
code.putln("0};")
def generate_argument_parsing_code(self, env, code):
# Generate PyArg_ParseTuple call for generic
# arguments, if any.
if self.entry.signature.has_dummy_arg and not self.self_in_stararg:
# get rid of unused argument warning
code.putln("%s = %s;" % (Naming.self_cname, Naming.self_cname))
old_error_label = code.new_error_label()
our_error_label = code.error_label
end_label = code.new_label("argument_unpacking_done")
has_kwonly_args = self.num_kwonly_args > 0
has_star_or_kw_args = self.star_arg is not None \
or self.starstar_arg is not None or has_kwonly_args
for arg in self.args:
if not arg.type.is_pyobject:
done = arg.type.create_from_py_utility_code(env)
if not done: pass # will fail later
if not self.signature_has_generic_args():
if has_star_or_kw_args:
error(self.pos, "This method cannot have * or keyword arguments")
self.generate_argument_conversion_code(code)
elif not self.signature_has_nongeneric_args():
# func(*args) or func(**kw) or func(*args, **kw)
self.generate_stararg_copy_code(code)
else:
positional_args = []
kw_only_args = []
for arg in self.args:
arg_entry = arg.entry
if arg.is_generic:
if arg.default:
if not arg.is_self_arg and not arg.is_type_arg:
if arg.kw_only:
kw_only_args.append(arg)
else:
positional_args.append(arg)
elif arg.kw_only:
kw_only_args.append(arg)
elif not arg.is_self_arg and not arg.is_type_arg:
positional_args.append(arg)
self.generate_tuple_and_keyword_parsing_code(
positional_args, kw_only_args, end_label, code)
code.error_label = old_error_label
if code.label_used(our_error_label):
if not code.label_used(end_label):
code.put_goto(end_label)
code.put_label(our_error_label)
if has_star_or_kw_args:
self.generate_arg_decref(self.star_arg, code)
if self.starstar_arg:
if self.starstar_arg.entry.xdecref_cleanup:
code.put_var_xdecref(self.starstar_arg.entry)
else:
code.put_var_decref(self.starstar_arg.entry)
code.putln('__Pyx_AddTraceback("%s");' % self.entry.qualified_name)
# The arguments are put into the closure one after the
# other, so when type errors are found, all references in
# the closure instance must be properly ref-counted to
# facilitate generic closure instance deallocation. In
# the case of an argument type error, it's best to just
# DECREF+clear the already handled references, as this
# frees their references as early as possible.
for arg in self.args:
if arg.type.is_pyobject and arg.entry.in_closure:
code.put_var_xdecref_clear(arg.entry)
if self.needs_closure:
code.put_decref(Naming.cur_scope_cname, self.local_scope.scope_class.type)
code.put_finish_refcount_context()
code.putln("return %s;" % self.error_value())
if code.label_used(end_label):
code.put_label(end_label)
def generate_arg_assignment(self, arg, item, code):
if arg.type.is_pyobject:
if arg.is_generic:
item = PyrexTypes.typecast(arg.type, PyrexTypes.py_object_type, item)
entry = arg.entry
code.putln("%s = %s;" % (entry.cname, item))
if entry.in_closure:
code.put_var_incref(entry)
else:
func = arg.type.from_py_function
if func:
code.putln("%s = %s(%s); %s" % (
arg.entry.cname,
func,
item,
code.error_goto_if(arg.type.error_condition(arg.entry.cname), arg.pos)))
else:
error(arg.pos, "Cannot convert Python object argument to type '%s'" % arg.type)
def generate_arg_xdecref(self, arg, code):
if arg:
code.put_var_xdecref(arg.entry)
def generate_arg_decref(self, arg, code):
if arg:
code.put_var_decref(arg.entry)
def generate_stararg_copy_code(self, code):
if not self.star_arg:
code.globalstate.use_utility_code(raise_argtuple_invalid_utility_code)
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()))
code.putln("}")
code.globalstate.use_utility_code(keyword_string_check_utility_code)
if self.starstar_arg:
if self.star_arg:
kwarg_check = "unlikely(%s)" % Naming.kwds_cname
else:
kwarg_check = "%s" % Naming.kwds_cname
else:
kwarg_check = "unlikely(%s) && unlikely(PyDict_Size(%s) > 0)" % (
Naming.kwds_cname, Naming.kwds_cname)
code.putln(
"if (%s && unlikely(!__Pyx_CheckKeywordStrings(%s, \"%s\", %d))) return %s;" % (
kwarg_check, Naming.kwds_cname, self.name,
bool(self.starstar_arg), self.error_value()))
if self.starstar_arg:
code.putln("%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:
# 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:
code.putln("{")
code.put_decref_clear(self.starstar_arg.entry.cname, py_object_type)
code.putln("return %s;" % self.error_value())
code.putln("}")
else:
code.putln("return %s;" % self.error_value())
code.put_gotref(self.star_arg.entry.cname)
code.put_incref(Naming.self_cname, py_object_type)
code.put_giveref(Naming.self_cname)
code.putln("PyTuple_SET_ITEM(%s, 0, %s);" % (
self.star_arg.entry.cname, Naming.self_cname))
temp = code.funcstate.allocate_temp(PyrexTypes.c_py_ssize_t_type, manage_ref=False)
code.putln("for (%s=0; %s < PyTuple_GET_SIZE(%s); %s++) {" % (
temp, temp, Naming.args_cname, temp))
code.putln("PyObject* item = PyTuple_GET_ITEM(%s, %s);" % (
Naming.args_cname, temp))
code.put_incref("item", py_object_type)
code.put_giveref("item")
code.putln("PyTuple_SET_ITEM(%s, %s+1, item);" % (
self.star_arg.entry.cname, temp))
code.putln("}")
code.funcstate.release_temp(temp)
self.star_arg.entry.xdecref_cleanup = 0
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.xdecref_cleanup = 0
def generate_tuple_and_keyword_parsing_code(self, positional_args,
kw_only_args, success_label, code):
argtuple_error_label = code.new_label("argtuple_error")
min_positional_args = self.num_required_args - self.num_required_kw_args
if len(self.args) > 0 and (self.args[0].is_self_arg or self.args[0].is_type_arg):
min_positional_args -= 1
max_positional_args = len(positional_args)
has_fixed_positional_count = not self.star_arg and \
min_positional_args == max_positional_args
code.globalstate.use_utility_code(raise_double_keywords_utility_code)
code.globalstate.use_utility_code(raise_argtuple_invalid_utility_code)
if self.num_required_kw_args:
code.globalstate.use_utility_code(raise_keyword_required_utility_code)
if self.starstar_arg or self.star_arg:
self.generate_stararg_init_code(max_positional_args, code)
# --- optimised code when we receive keyword arguments
if self.num_required_kw_args:
likely_hint = "likely"
else:
likely_hint = "unlikely"
code.putln("if (%s(%s)) {" % (likely_hint, Naming.kwds_cname))
self.generate_keyword_unpacking_code(
min_positional_args, max_positional_args,
has_fixed_positional_count,
positional_args, kw_only_args, argtuple_error_label, code)
# --- optimised code when we do not receive any keyword arguments
if (self.num_required_kw_args and min_positional_args > 0) or min_positional_args == max_positional_args:
# Python raises arg tuple related errors first, so we must
# check the length here
if min_positional_args == max_positional_args and not self.star_arg:
compare = '!='
else:
compare = '<'
code.putln('} else if (PyTuple_GET_SIZE(%s) %s %d) {' % (
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))
code.put_goto(argtuple_error_label)
code.putln('} else {')
for i, arg in enumerate(kw_only_args):
if not arg.default:
pystring_cname = code.intern_identifier(arg.name)
# required keyword-only argument missing
code.put('__Pyx_RaiseKeywordRequired("%s", %s); ' % (
self.name,
pystring_cname))
code.putln(code.error_goto(self.pos))
break
elif min_positional_args == max_positional_args:
# parse the exact number of positional arguments from the
# args tuple
code.putln('} else {')
for i, arg in enumerate(positional_args):
item = "PyTuple_GET_ITEM(%s, %d)" % (Naming.args_cname, i)
self.generate_arg_assignment(arg, item, code)
self.generate_arg_default_assignments(code)
else:
# parse the positional arguments from the variable length
# args tuple
code.putln('} else {')
self.generate_arg_default_assignments(code)
code.putln('switch (PyTuple_GET_SIZE(%s)) {' % Naming.args_cname)
if self.star_arg:
code.putln('default:')
reversed_args = list(enumerate(positional_args))[::-1]
for i, arg in reversed_args:
if i >= min_positional_args-1:
if min_positional_args > 1:
code.putln('case %2d:' % (i+1)) # pure code beautification
else:
code.put('case %2d: ' % (i+1))
item = "PyTuple_GET_ITEM(%s, %d)" % (Naming.args_cname, i)
self.generate_arg_assignment(arg, item, code)
if min_positional_args == 0:
code.put('case 0: ')
code.putln('break;')
if self.star_arg:
if min_positional_args:
for i in range(min_positional_args-1, -1, -1):
code.putln('case %2d:' % i)
code.put_goto(argtuple_error_label)
else:
code.put('default: ')
code.put_goto(argtuple_error_label)
code.putln('}')
code.putln('}')
if code.label_used(argtuple_error_label):
code.put_goto(success_label)
code.put_label(argtuple_error_label)
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))
code.putln(code.error_goto(self.pos))
def generate_arg_default_assignments(self, code):
for arg in self.args:
if arg.is_generic and arg.default:
code.putln(
"%s = %s;" % (
arg.entry.cname,
arg.calculate_default_value_code(code)))
def generate_stararg_init_code(self, max_positional_args, code):
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()))
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))
code.put('%s = PyTuple_GetSlice(%s, %d, PyTuple_GET_SIZE(%s)); ' % (
self.star_arg.entry.cname, Naming.args_cname,
max_positional_args, Naming.args_cname))
code.put_gotref(self.star_arg.entry.cname)
if self.starstar_arg:
code.putln("")
code.putln("if (unlikely(!%s)) {" % self.star_arg.entry.cname)
code.put_decref(self.starstar_arg.entry.cname, py_object_type)
code.putln('return %s;' % self.error_value())
code.putln('}')
else:
code.putln("if (unlikely(!%s)) return %s;" % (
self.star_arg.entry.cname, self.error_value()))
code.putln('} else {')
code.put("%s = %s; " % (self.star_arg.entry.cname, Naming.empty_tuple))
code.put_incref(Naming.empty_tuple, py_object_type)
code.putln('}')
def generate_keyword_unpacking_code(self, min_positional_args, max_positional_args,
has_fixed_positional_count, positional_args,
kw_only_args, argtuple_error_label, code):
all_args = tuple(positional_args) + tuple(kw_only_args)
max_args = len(all_args)
code.putln("Py_ssize_t kw_args = PyDict_Size(%s);" %
Naming.kwds_cname)
# the 'values' array collects borrowed references to arguments
# before doing any type coercion etc.
code.putln("PyObject* values[%d] = {%s};" % (
max_args, ','.join('0'*max_args)))
# assign borrowed Python default values to the values array,
# so that they can be overwritten by received arguments below
for i, arg in enumerate(all_args):
if arg.default and arg.type.is_pyobject:
default_value = arg.calculate_default_value_code(code)
code.putln('values[%d] = %s;' % (i, arg.type.as_pyobject(default_value)))
# parse the args tuple and check that it's not too long
code.putln('switch (PyTuple_GET_SIZE(%s)) {' % Naming.args_cname)
if self.star_arg:
code.putln('default:')
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))
code.putln('case 0: break;')
if not self.star_arg:
code.put('default: ') # more arguments than allowed
code.put_goto(argtuple_error_label)
code.putln('}')
# now fill up the positional/required arguments with values
# from the kw dict
if self.num_required_args or max_positional_args > 0:
last_required_arg = -1
for i, arg in enumerate(all_args):
if not arg.default:
last_required_arg = i
if last_required_arg < max_positional_args:
last_required_arg = max_positional_args-1
num_required_args = self.num_required_args
if max_positional_args > 0:
code.putln('switch (PyTuple_GET_SIZE(%s)) {' % Naming.args_cname)
for i, arg in enumerate(all_args[:last_required_arg+1]):
if max_positional_args > 0 and i <= max_positional_args:
if self.star_arg and i == max_positional_args:
code.putln('default:')
else:
code.putln('case %2d:' % i)
pystring_cname = code.intern_identifier(arg.name)
if arg.default:
if arg.kw_only:
# handled separately below
continue
code.putln('if (kw_args > 0) {')
code.putln('PyObject* value = PyDict_GetItem(%s, %s);' % (
Naming.kwds_cname, pystring_cname))
code.putln('if (value) { values[%d] = value; kw_args--; }' % i)
code.putln('}')
else:
num_required_args -= 1
code.putln('values[%d] = PyDict_GetItem(%s, %s);' % (
i, Naming.kwds_cname, pystring_cname))
code.putln('if (likely(values[%d])) kw_args--;' % i);
if i < min_positional_args:
if i == 0:
# special case: we know arg 0 is missing
code.put('else ')
code.put_goto(argtuple_error_label)
else:
# print the correct number of values (args or
# kwargs) that were passed into positional
# arguments up to this point
code.putln('else {')
code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d, %d); ' % (
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.put('__Pyx_RaiseKeywordRequired("%s", %s); ' %(
self.name, pystring_cname))
code.putln(code.error_goto(self.pos))
code.putln('}')
if max_positional_args > 0:
code.putln('}')
if kw_only_args and not self.starstar_arg:
# unpack optional keyword-only arguments
# checking for interned strings in a dict is faster than iterating
# but it's too likely that we must iterate if we expect **kwargs
optional_args = []
for i, arg in enumerate(all_args[max_positional_args:]):
if not arg.kw_only or not arg.default:
continue
optional_args.append((i+max_positional_args, arg))
if optional_args:
# this mimics an unrolled loop so that we can "break" out of it
code.putln('while (kw_args > 0) {')
code.putln('PyObject* value;')
for i, arg in optional_args:
pystring_cname = code.intern_identifier(arg.name)
code.putln(
'value = PyDict_GetItem(%s, %s);' % (
Naming.kwds_cname, pystring_cname))
code.putln(
'if (value) { values[%d] = value; if (!(--kw_args)) break; }' % i)
code.putln('break;')
code.putln('}')
code.putln('if (unlikely(kw_args > 0)) {')
# non-positional/-required kw args left in dict: default args,
# kw-only args, **kwargs or error
#
# This is sort of a catch-all: except for checking required
# arguments, this will always do the right thing for unpacking
# keyword arguments, so that we can concentrate on optimising
# common cases above.
if max_positional_args == 0:
pos_arg_count = "0"
elif self.star_arg:
code.putln("const Py_ssize_t used_pos_args = (PyTuple_GET_SIZE(%s) < %d) ? PyTuple_GET_SIZE(%s) : %d;" % (
Naming.args_cname, max_positional_args,
Naming.args_cname, max_positional_args))
pos_arg_count = "used_pos_args"
else:
pos_arg_count = "PyTuple_GET_SIZE(%s)" % Naming.args_cname
code.globalstate.use_utility_code(parse_keywords_utility_code)
code.put(
'if (unlikely(__Pyx_ParseOptionalKeywords(%s, %s, %s, values, %s, "%s") < 0)) ' % (
Naming.kwds_cname,
Naming.pykwdlist_cname,
self.starstar_arg and self.starstar_arg.entry.cname or '0',
pos_arg_count,
self.name))
code.putln(code.error_goto(self.pos))
code.putln('}')
# convert arg values to their final type and assign them
for i, arg in enumerate(all_args):
if arg.default and not arg.type.is_pyobject:
code.putln("if (values[%d]) {" % i)
self.generate_arg_assignment(arg, "values[%d]" % i, code)
if arg.default and not arg.type.is_pyobject:
code.putln('} else {')
code.putln(
"%s = %s;" % (
arg.entry.cname,
arg.calculate_default_value_code(code)))
code.putln('}')
def generate_argument_conversion_code(self, code):
# Generate code to convert arguments from signature type to
# declared type, if needed. Also copies signature arguments
# into closure fields.
for arg in self.args:
if arg.needs_conversion:
self.generate_arg_conversion(arg, code)
elif arg.entry.in_closure:
code.putln('%s = %s;' % (arg.entry.cname, arg.hdr_cname))
if arg.type.is_pyobject:
code.put_var_incref(arg.entry)
def generate_arg_conversion(self, arg, code):
# Generate conversion code for one argument.
old_type = arg.hdr_type
new_type = arg.type
if old_type.is_pyobject:
if arg.default:
code.putln("if (%s) {" % arg.hdr_cname)
else:
code.putln("assert(%s); {" % arg.hdr_cname)
self.generate_arg_conversion_from_pyobject(arg, code)
code.putln("}")
elif new_type.is_pyobject:
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))
else:
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
func = new_type.from_py_function
# copied from CoerceFromPyTypeNode
if func:
lhs = arg.entry.cname
rhs = "%s(%s)" % (func, arg.hdr_cname)
if new_type.is_enum:
rhs = PyrexTypes.typecast(new_type, PyrexTypes.c_long_type, rhs)
code.putln("%s = %s; %s" % (
lhs,
rhs,
code.error_goto_if(new_type.error_condition(arg.entry.cname), arg.pos)))
else:
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
func = old_type.to_py_function
if func:
code.putln("%s = %s(%s); %s" % (
arg.entry.cname,
func,
arg.hdr_cname,
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)
def generate_argument_type_tests(self, code):
# Generate type tests for args whose signature
# type is PyObject * and whose declared type is
# a subtype thereof.
for arg in self.args:
if arg.needs_type_test:
self.generate_arg_type_test(arg, code)
elif not arg.accept_none and arg.type.is_pyobject:
self.generate_arg_none_check(arg, code)
def error_value(self):
return self.entry.signature.error_value
def caller_will_check_exceptions(self):
return 1
class OverrideCheckNode(StatNode):
# A Node for dispatching to the def method if it
# is overriden.
#
# py_func
#
# args
# func_temp
# body
child_attrs = ['body']
body = None
def analyse_expressions(self, env):
self.args = env.arg_entries
if self.py_func.is_module_scope:
first_arg = 0
else:
first_arg = 1
import ExprNodes
self.func_node = ExprNodes.RawCNameExprNode(self.pos, py_object_type)
call_tuple = ExprNodes.TupleNode(self.pos, args=[ExprNodes.NameNode(self.pos, name=arg.name) for arg in self.args[first_arg:]])
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:]])
self.body = ReturnStatNode(self.pos, value=call_node)
self.body.analyse_expressions(env)
def generate_execution_code(self, code):
interned_attr_cname = code.intern_identifier(self.py_func.entry.name)
# Check to see if we are an extension type
if self.py_func.is_module_scope:
self_arg = "((PyObject *)%s)" % Naming.module_cname
else:
self_arg = "((PyObject *)%s)" % self.args[0].cname
code.putln("/* Check if called by wrapper */")
code.putln("if (unlikely(%s)) ;" % Naming.skip_dispatch_cname)
code.putln("/* Check if overriden in Python */")
if self.py_func.is_module_scope:
code.putln("else {")
else:
code.putln("else if (unlikely(Py_TYPE(%s)->tp_dictoffset != 0)) {" % self_arg)
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
err = code.error_goto_if_null(func_node_temp, self.pos)
code.putln("%s = PyObject_GetAttr(%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) != (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("}")
code.put_decref_clear(func_node_temp, PyrexTypes.py_object_type)
code.funcstate.release_temp(func_node_temp)
code.putln("}")
class ClassDefNode(StatNode, BlockNode):
pass
class PyClassDefNode(ClassDefNode):
# A Python class definition.
#
# name EncodedString Name of the class
# doc string or None
# body StatNode Attribute definition code
# entry Symtab.Entry
# scope PyClassScope
# decorators [DecoratorNode] list of decorators or None
#
# The following subnodes are constructed internally:
#
# dict DictNode Class dictionary
# classobj ClassNode Class object
# target NameNode Variable to assign class object to
child_attrs = ["body", "dict", "classobj", "target"]
decorators = None
def __init__(self, pos, name, bases, doc, body, decorators = None):
StatNode.__init__(self, pos)
self.name = name
self.doc = doc
self.body = body
self.decorators = decorators
import ExprNodes
self.dict = ExprNodes.DictNode(pos, key_value_pairs = [])
if self.doc and Options.docstrings:
doc = embed_position(self.pos, self.doc)
# FIXME: correct string node?
doc_node = ExprNodes.StringNode(pos, value = doc)
else:
doc_node = None
self.classobj = ExprNodes.ClassNode(pos, name = name,
bases = bases, dict = self.dict, doc = doc_node)
self.target = ExprNodes.NameNode(pos, name = name)
def as_cclass(self):
"""
Return this node as if it were declared as an extension class
"""
bases = self.classobj.bases.args
if len(bases) == 0:
base_class_name = None
base_class_module = None
elif len(bases) == 1:
base = bases[0]
path = []
from ExprNodes import AttributeNode, NameNode
while isinstance(base, AttributeNode):
path.insert(0, base.attribute)
base = base.obj
if isinstance(base, NameNode):
path.insert(0, base.name)
base_class_name = path[-1]
if len(path) > 1:
base_class_module = u'.'.join(path[:-1])
else:
base_class_module = None
else:
error(self.classobj.bases.args.pos, "Invalid base class")
else:
error(self.classobj.bases.args.pos, "C class may only have one base class")
return None
return CClassDefNode(self.pos,
visibility = 'private',
module_name = None,
class_name = self.name,
base_class_module = base_class_module,
base_class_name = base_class_name,
decorators = self.decorators,
body = self.body,
in_pxd = False,
doc = self.doc)
def create_scope(self, env):
genv = env
while env.is_py_class_scope or env.is_c_class_scope:
env = env.outer_scope
cenv = self.scope = PyClassScope(name = self.name, outer_scope = genv)
return cenv
def analyse_declarations(self, env):
self.target.analyse_target_declaration(env)
cenv = self.create_scope(env)
cenv.directives = env.directives
cenv.class_obj_cname = self.target.entry.cname
self.body.analyse_declarations(cenv)
def analyse_expressions(self, env):
self.dict.analyse_expressions(env)
self.classobj.analyse_expressions(env)
genv = env.global_scope()
cenv = self.scope
self.body.analyse_expressions(cenv)
self.target.analyse_target_expression(env, self.classobj)
def generate_function_definitions(self, env, code):
self.body.generate_function_definitions(self.scope, code)
def generate_execution_code(self, code):
code.pyclass_stack.append(self)
cenv = self.scope
self.dict.generate_evaluation_code(code)
self.classobj.generate_evaluation_code(code)
cenv.namespace_cname = cenv.class_obj_cname = self.classobj.result()
self.body.generate_execution_code(code)
self.target.generate_assignment_code(self.classobj, code)
self.dict.generate_disposal_code(code)
self.dict.free_temps(code)
code.pyclass_stack.pop()
class CClassDefNode(ClassDefNode):
# An extension type definition.
#
# visibility 'private' or 'public' or 'extern'
# typedef_flag boolean
# api boolean
# module_name string or None For import of extern type objects
# class_name string Unqualified name of class
# as_name string or None Name to declare as in this scope
# base_class_module string or None Module containing the base class
# base_class_name string or None Name of the base class
# objstruct_name string or None Specified C name of object struct
# typeobj_name string or None Specified C name of type object
# in_pxd boolean Is in a .pxd file
# decorators [DecoratorNode] list of decorators or None
# doc string or None
# body StatNode or None
# entry Symtab.Entry
# base_type PyExtensionType or None
# buffer_defaults_node DictNode or None Declares defaults for a buffer
# buffer_defaults_pos
child_attrs = ["body"]
buffer_defaults_node = None
buffer_defaults_pos = None
typedef_flag = False
api = False
objstruct_name = None
typeobj_name = None
decorators = None
def analyse_declarations(self, env):
#print "CClassDefNode.analyse_declarations:", self.class_name
#print "...visibility =", self.visibility
#print "...module_name =", self.module_name
import Buffer
if self.buffer_defaults_node:
buffer_defaults = Buffer.analyse_buffer_options(self.buffer_defaults_pos,
env, [], self.buffer_defaults_node,
need_complete=False)
else:
buffer_defaults = None
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")
self.base_type = None
# Now that module imports are cached, we need to
# import the modules for extern classes.
if self.module_name:
self.module = None
for module in env.cimported_modules:
if module.name == self.module_name:
self.module = module
if self.module is None:
self.module = ModuleScope(self.module_name, None, env.context)
self.module.has_extern_class = 1
env.add_imported_module(self.module)
if self.base_class_name:
if self.base_class_module:
base_class_scope = env.find_module(self.base_class_module, self.pos)
else:
base_class_scope = env
if self.base_class_name == 'object':
# extension classes are special and don't need to inherit from object
if base_class_scope is None or base_class_scope.lookup('object') is None:
self.base_class_name = None
self.base_class_module = None
base_class_scope = None
if base_class_scope:
base_class_entry = base_class_scope.find(self.base_class_name, self.pos)
if base_class_entry:
if not base_class_entry.is_type:
error(self.pos, "'%s' is not a type name" % self.base_class_name)
elif not base_class_entry.type.is_extension_type:
error(self.pos, "'%s' is not an extension type" % self.base_class_name)
elif not base_class_entry.type.is_complete():
error(self.pos, "Base class '%s' is incomplete" % self.base_class_name)
else:
self.base_type = base_class_entry.type
has_body = self.body is not None
if self.module_name and self.visibility != 'extern':
module_path = self.module_name.split(".")
home_scope = env.find_imported_module(module_path, self.pos)
if not home_scope:
return
else:
home_scope = env
if self.visibility == 'extern':
if self.module_name == '__builtin__' and self.class_name in Builtin.builtin_types:
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,
visibility = self.visibility,
typedef_flag = self.typedef_flag,
api = self.api,
buffer_defaults = buffer_defaults)
if home_scope is not env and self.visibility == 'extern':
env.add_imported_entry(self.class_name, self.entry, pos)
self.scope = scope = self.entry.type.scope
if scope is not None:
scope.directives = env.directives
if self.doc and Options.docstrings:
scope.doc = embed_position(self.pos, self.doc)
if has_body:
self.body.analyse_declarations(scope)
if self.in_pxd:
scope.defined = 1
else:
scope.implemented = 1
env.allocate_vtable_names(self.entry)
def analyse_expressions(self, env):
if self.body:
scope = self.entry.type.scope
self.body.analyse_expressions(scope)
def generate_function_definitions(self, env, code):
if self.body:
self.body.generate_function_definitions(
self.entry.type.scope, code)
def generate_execution_code(self, code):
# This is needed to generate evaluation code for
# default values of method arguments.
if self.body:
self.body.generate_execution_code(code)
def annotate(self, code):
if self.body:
self.body.annotate(code)
class PropertyNode(StatNode):
# Definition of a property in an extension type.
#
# name string
# doc EncodedString or None Doc string
# body StatListNode
child_attrs = ["body"]
def analyse_declarations(self, env):
entry = env.declare_property(self.name, self.doc, self.pos)
if entry:
entry.scope.directives = env.directives
self.body.analyse_declarations(entry.scope)
def analyse_expressions(self, env):
self.body.analyse_expressions(env)
def generate_function_definitions(self, env, code):
self.body.generate_function_definitions(env, code)
def generate_execution_code(self, code):
pass
def annotate(self, code):
self.body.annotate(code)
class GlobalNode(StatNode):
# Global variable declaration.
#
# names [string]
child_attrs = []
def analyse_declarations(self, env):
for name in self.names:
env.declare_global(name, self.pos)
def analyse_expressions(self, env):
pass
def generate_execution_code(self, code):
pass
class ExprStatNode(StatNode):
# Expression used as a statement.
#
# expr ExprNode
child_attrs = ["expr"]
def analyse_declarations(self, env):
import ExprNodes
if isinstance(self.expr, ExprNodes.GeneralCallNode):
func = self.expr.function.as_cython_attribute()
if func == u'declare':
args, kwds = self.expr.explicit_args_kwds()
if len(args):
error(self.expr.pos, "Variable names must be specified.")
for var, type_node in kwds.key_value_pairs:
type = type_node.analyse_as_type(env)
if type is None:
error(type_node.pos, "Unknown type")
else:
env.declare_var(var.value, type, var.pos, is_cdef = True)
self.__class__ = PassStatNode
def analyse_expressions(self, env):
self.expr.analyse_expressions(env)
def generate_execution_code(self, code):
self.expr.generate_evaluation_code(code)
if not self.expr.is_temp and self.expr.result():
code.putln("%s;" % self.expr.result())
self.expr.generate_disposal_code(code)
self.expr.free_temps(code)
def generate_function_definitions(self, env, code):
self.expr.generate_function_definitions(env, code)
def annotate(self, code):
self.expr.annotate(code)
class AssignmentNode(StatNode):
# Abstract base class for assignment nodes.
#
# The analyse_expressions and generate_execution_code
# phases of assignments are split into two sub-phases
# each, to enable all the right hand sides of a
# parallel assignment to be evaluated before assigning
# to any of the left hand sides.
def analyse_expressions(self, env):
self.analyse_types(env)
# def analyse_expressions(self, env):
# self.analyse_expressions_1(env)
# self.analyse_expressions_2(env)
def generate_execution_code(self, code):
self.generate_rhs_evaluation_code(code)
self.generate_assignment_code(code)
class SingleAssignmentNode(AssignmentNode):
# The simplest case:
#
# a = b
#
# lhs ExprNode Left hand side
# rhs ExprNode Right hand side
# first bool Is this guaranteed the first assignment to lhs?
child_attrs = ["lhs", "rhs"]
first = False
declaration_only = False
def analyse_declarations(self, env):
import ExprNodes
# handle declarations of the form x = cython.foo()
if isinstance(self.rhs, ExprNodes.CallNode):
func_name = self.rhs.function.as_cython_attribute()
if func_name:
args, kwds = self.rhs.explicit_args_kwds()
if func_name in ['declare', 'typedef']:
if len(args) > 2 or kwds is not None:
error(rhs.pos, "Can only declare one type at a time.")
return
type = args[0].analyse_as_type(env)
if type is None:
error(args[0].pos, "Unknown type")
return
lhs = self.lhs
if func_name == 'declare':
if isinstance(lhs, ExprNodes.NameNode):
vars = [(lhs.name, lhs.pos)]
elif isinstance(lhs, ExprNodes.TupleNode):
vars = [(var.name, var.pos) for var in lhs.args]
else:
error(lhs.pos, "Invalid declaration")
return
for var, pos in vars:
env.declare_var(var, type, pos, is_cdef = True)
if len(args) == 2:
# we have a value
self.rhs = args[1]
else:
self.declaration_only = True
else:
self.declaration_only = True
if not isinstance(lhs, ExprNodes.NameNode):
error(lhs.pos, "Invalid declaration.")
env.declare_typedef(lhs.name, type, self.pos, visibility='private')
elif func_name in ['struct', 'union']:
self.declaration_only = True
if len(args) > 0 or kwds is None:
error(rhs.pos, "Struct or union members must be given by name.")
return
members = []
for member, type_node in kwds.key_value_pairs:
type = type_node.analyse_as_type(env)
if type is None:
error(type_node.pos, "Unknown type")
else:
members.append((member.value, type, member.pos))
if len(members) < len(kwds.key_value_pairs):
return
if not isinstance(self.lhs, ExprNodes.NameNode):
error(self.lhs.pos, "Invalid declaration.")
name = self.lhs.name
scope = StructOrUnionScope(name)
env.declare_struct_or_union(name, func_name, scope, False, self.rhs.pos)
for member, type, pos in members:
scope.declare_var(member, type, pos)
if self.declaration_only:
return
else:
self.lhs.analyse_target_declaration(env)
def analyse_types(self, env, use_temp = 0):
self.rhs.analyse_types(env)
self.lhs.analyse_target_types(env)
self.lhs.gil_assignment_check(env)
self.rhs = self.rhs.coerce_to(self.lhs.type, env)
if use_temp:
self.rhs = self.rhs.coerce_to_temp(env)
def generate_rhs_evaluation_code(self, code):
self.rhs.generate_evaluation_code(code)
def generate_assignment_code(self, code):
self.lhs.generate_assignment_code(self.rhs, code)
def generate_function_definitions(self, env, code):
self.rhs.generate_function_definitions(env, code)
def annotate(self, code):
self.lhs.annotate(code)
self.rhs.annotate(code)
class CascadedAssignmentNode(AssignmentNode):
# An assignment with multiple left hand sides:
#
# a = b = c
#
# lhs_list [ExprNode] Left hand sides
# rhs ExprNode Right hand sides
#
# Used internally:
#
# coerced_rhs_list [ExprNode] RHS coerced to type of each LHS
child_attrs = ["lhs_list", "rhs", "coerced_rhs_list"]
coerced_rhs_list = None
def analyse_declarations(self, env):
for lhs in self.lhs_list:
lhs.analyse_target_declaration(env)
def analyse_types(self, env, use_temp = 0):
self.rhs.analyse_types(env)
if not self.rhs.is_simple():
if use_temp:
self.rhs = self.rhs.coerce_to_temp(env)
else:
self.rhs = self.rhs.coerce_to_simple(env)
from ExprNodes import CloneNode
self.coerced_rhs_list = []
for lhs in self.lhs_list:
lhs.analyse_target_types(env)
lhs.gil_assignment_check(env)
rhs = CloneNode(self.rhs)
rhs = rhs.coerce_to(lhs.type, env)
self.coerced_rhs_list.append(rhs)
def generate_rhs_evaluation_code(self, code):
self.rhs.generate_evaluation_code(code)
def generate_assignment_code(self, code):
for i in range(len(self.lhs_list)):
lhs = self.lhs_list[i]
rhs = self.coerced_rhs_list[i]
rhs.generate_evaluation_code(code)
lhs.generate_assignment_code(rhs, code)
# Assignment has disposed of the cloned RHS
self.rhs.generate_disposal_code(code)
self.rhs.free_temps(code)
def generate_function_definitions(self, env, code):
self.rhs.generate_function_definitions(env, code)
def annotate(self, code):
for i in range(len(self.lhs_list)):
lhs = self.lhs_list[i].annotate(code)
rhs = self.coerced_rhs_list[i].annotate(code)
self.rhs.annotate(code)
class ParallelAssignmentNode(AssignmentNode):
# A combined packing/unpacking assignment:
#
# a, b, c = d, e, f
#
# This has been rearranged by the parser into
#
# a = d ; b = e ; c = f
#
# but we must evaluate all the right hand sides
# before assigning to any of the left hand sides.
#
# stats [AssignmentNode] The constituent assignments
child_attrs = ["stats"]
def analyse_declarations(self, env):
for stat in self.stats:
stat.analyse_declarations(env)
def analyse_expressions(self, env):
for stat in self.stats:
stat.analyse_types(env, use_temp = 1)
# def analyse_expressions(self, env):
# for stat in self.stats:
# stat.analyse_expressions_1(env, use_temp = 1)
# for stat in self.stats:
# stat.analyse_expressions_2(env)
def generate_execution_code(self, code):
for stat in self.stats:
stat.generate_rhs_evaluation_code(code)
for stat in self.stats:
stat.generate_assignment_code(code)
def generate_function_definitions(self, env, code):
for stat in self.stats:
stat.generate_function_definitions(env, code)
def annotate(self, code):
for stat in self.stats:
stat.annotate(code)
class InPlaceAssignmentNode(AssignmentNode):
# An in place arithmetic operand:
#
# a += b
# a -= b
# ...
#
# lhs ExprNode Left hand side
# rhs ExprNode Right hand side
# op char one of "+-*/%^&|"
# dup (ExprNode) copy of lhs used for operation (auto-generated)
#
# This code is a bit tricky because in order to obey Python
# semantics the sub-expressions (e.g. indices) of the lhs must
# not be evaluated twice. So we must re-use the values calculated
# in evaluation phase for the assignment phase as well.
# Fortunately, the type of the lhs node is fairly constrained
# (it must be a NameNode, AttributeNode, or IndexNode).
child_attrs = ["lhs", "rhs"]
dup = None
def analyse_declarations(self, env):
self.lhs.analyse_target_declaration(env)
def analyse_types(self, env):
self.dup = self.create_dup_node(env) # re-assigns lhs to a shallow copy
self.rhs.analyse_types(env)
self.lhs.analyse_target_types(env)
import ExprNodes
if self.lhs.type.is_pyobject:
self.rhs = self.rhs.coerce_to_pyobject(env)
elif self.rhs.type.is_pyobject or (self.lhs.type.is_numeric and self.rhs.type.is_numeric):
self.rhs = self.rhs.coerce_to(self.lhs.type, env)
if self.lhs.type.is_pyobject:
self.result_value_temp = ExprNodes.PyTempNode(self.pos, env)
self.result_value = self.result_value_temp.coerce_to(self.lhs.type, env)
def generate_execution_code(self, code):
import ExprNodes
self.rhs.generate_evaluation_code(code)
self.dup.generate_subexpr_evaluation_code(code)
if self.dup.is_temp:
self.dup.allocate_temp_result(code)
# self.dup.generate_result_code is run only if it is not buffer access
if self.operator == "**":
extra = ", Py_None"
else:
extra = ""
if self.lhs.type.is_pyobject:
if isinstance(self.lhs, ExprNodes.IndexNode) and self.lhs.is_buffer_access:
error(self.pos, "In-place operators not allowed on object buffers in this release.")
self.dup.generate_result_code(code)
self.result_value_temp.allocate(code)
code.putln(
"%s = %s(%s, %s%s); %s" % (
self.result_value.result(),
self.py_operation_function(),
self.dup.py_result(),
self.rhs.py_result(),
extra,
code.error_goto_if_null(self.result_value.py_result(), self.pos)))
code.put_gotref(self.result_value.py_result())
self.result_value.generate_evaluation_code(code) # May be a type check...
self.rhs.generate_disposal_code(code)
self.rhs.free_temps(code)
self.dup.generate_disposal_code(code)
self.dup.free_temps(code)
self.lhs.generate_assignment_code(self.result_value, code)
self.result_value_temp.release(code)
else:
c_op = self.operator
if c_op == "//":
c_op = "/"
elif c_op == "**":
error(self.pos, "No C inplace power operator")
elif self.lhs.type.is_complex:
error(self.pos, "Inplace operators not implemented for complex types.")
# have to do assignment directly to avoid side-effects
if isinstance(self.lhs, ExprNodes.IndexNode) and self.lhs.is_buffer_access:
self.lhs.generate_buffer_setitem_code(self.rhs, code, c_op)
else:
self.dup.generate_result_code(code)
code.putln("%s %s= %s;" % (self.lhs.result(), c_op, self.rhs.result()) )
self.rhs.generate_disposal_code(code)
self.rhs.free_temps(code)
if self.dup.is_temp:
self.dup.generate_subexpr_disposal_code(code)
self.dup.free_subexpr_temps(code)
def create_dup_node(self, env):
import ExprNodes
self.dup = self.lhs
self.dup.analyse_types(env)
if isinstance(self.lhs, ExprNodes.NameNode):
target_lhs = ExprNodes.NameNode(self.dup.pos,
name = self.dup.name,
is_temp = self.dup.is_temp,
entry = self.dup.entry)
elif isinstance(self.lhs, ExprNodes.AttributeNode):
target_lhs = ExprNodes.AttributeNode(self.dup.pos,
obj = ExprNodes.CloneNode(self.lhs.obj),
attribute = self.dup.attribute,
is_temp = self.dup.is_temp)
elif isinstance(self.lhs, ExprNodes.IndexNode):
if self.lhs.index:
index = ExprNodes.CloneNode(self.lhs.index)
else:
index = None
if self.lhs.indices:
indices = [ExprNodes.CloneNode(x) for x in self.lhs.indices]
else:
indices = []
target_lhs = ExprNodes.IndexNode(self.dup.pos,
base = ExprNodes.CloneNode(self.dup.base),
index = index,
indices = indices,
is_temp = self.dup.is_temp)
else:
assert False, "Unsupported node: %s" % type(self.lhs)
self.lhs = target_lhs
return self.dup
def py_operation_function(self):
return self.py_functions[self.operator]
py_functions = {
"|": "PyNumber_InPlaceOr",
"^": "PyNumber_InPlaceXor",
"&": "PyNumber_InPlaceAnd",
"+": "PyNumber_InPlaceAdd",
"-": "PyNumber_InPlaceSubtract",
"*": "PyNumber_InPlaceMultiply",
"/": "__Pyx_PyNumber_InPlaceDivide",
"%": "PyNumber_InPlaceRemainder",
"<<": "PyNumber_InPlaceLshift",
">>": "PyNumber_InPlaceRshift",
"**": "PyNumber_InPlacePower",
"//": "PyNumber_InPlaceFloorDivide",
}
def annotate(self, code):
self.lhs.annotate(code)
self.rhs.annotate(code)
self.dup.annotate(code)
def create_binop_node(self):
import ExprNodes
return ExprNodes.binop_node(self.pos, self.operator, self.lhs, self.rhs)
class PrintStatNode(StatNode):
# print statement
#
# arg_tuple TupleNode
# stream ExprNode or None (stdout)
# append_newline boolean
child_attrs = ["arg_tuple", "stream"]
def analyse_expressions(self, env):
if self.stream:
self.stream.analyse_expressions(env)
self.stream = self.stream.coerce_to_pyobject(env)
self.arg_tuple.analyse_expressions(env)
self.arg_tuple = self.arg_tuple.coerce_to_pyobject(env)
env.use_utility_code(printing_utility_code)
if len(self.arg_tuple.args) == 1 and self.append_newline:
env.use_utility_code(printing_one_utility_code)
nogil_check = Node.gil_error
gil_message = "Python print statement"
def generate_execution_code(self, code):
if self.stream:
self.stream.generate_evaluation_code(code)
stream_result = self.stream.py_result()
else:
stream_result = '0'
if len(self.arg_tuple.args) == 1 and self.append_newline:
arg = self.arg_tuple.args[0]
arg.generate_evaluation_code(code)
code.putln(
"if (__Pyx_PrintOne(%s, %s) < 0) %s" % (
stream_result,
arg.py_result(),
code.error_goto(self.pos)))
arg.generate_disposal_code(code)
arg.free_temps(code)
else:
self.arg_tuple.generate_evaluation_code(code)
code.putln(
"if (__Pyx_Print(%s, %s, %d) < 0) %s" % (
stream_result,
self.arg_tuple.py_result(),
self.append_newline,
code.error_goto(self.pos)))
self.arg_tuple.generate_disposal_code(code)
self.arg_tuple.free_temps(code)
if self.stream:
self.stream.generate_disposal_code(code)
self.stream.free_temps(code)
def generate_function_definitions(self, env, code):
if self.stream:
self.stream.generate_function_definitions(env, code)
self.arg_tuple.generate_function_definitions(env, code)
def annotate(self, code):
if self.stream:
self.stream.annotate(code)
self.arg_tuple.annotate(code)
class ExecStatNode(StatNode):
# exec statement
#
# args [ExprNode]
child_attrs = ["args"]
def analyse_expressions(self, env):
for i, arg in enumerate(self.args):
arg.analyse_expressions(env)
arg = arg.coerce_to_pyobject(env)
self.args[i] = arg
env.use_utility_code(Builtin.pyexec_utility_code)
nogil_check = Node.gil_error
gil_message = "Python exec statement"
def generate_execution_code(self, code):
args = []
for arg in self.args:
arg.generate_evaluation_code(code)
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_PyRun(%s, %s, %s);" % (
(temp_result,) + args))
for arg in self.args:
arg.generate_disposal_code(code)
arg.free_temps(code)
code.putln(
code.error_goto_if_null(temp_result, self.pos))
code.put_gotref(temp_result)
code.put_decref_clear(temp_result, py_object_type)
code.funcstate.release_temp(temp_result)
def annotate(self, code):
for arg in self.args:
arg.annotate(code)
class DelStatNode(StatNode):
# del statement
#
# args [ExprNode]
child_attrs = ["args"]
def analyse_declarations(self, env):
for arg in self.args:
arg.analyse_target_declaration(env)
def analyse_expressions(self, env):
for arg in self.args:
arg.analyse_target_expression(env, None)
if arg.type.is_pyobject:
pass
elif arg.type.is_ptr and arg.type.base_type.is_cpp_class:
self.cpp_check(env)
elif arg.type.is_cpp_class:
error(arg.pos, "Deletion of non-heap C++ object")
else:
error(arg.pos, "Deletion of non-Python, non-C++ object")
#arg.release_target_temp(env)
def nogil_check(self, env):
for arg in self.args:
if arg.type.is_pyobject:
self.gil_error()
gil_message = "Deleting Python object"
def generate_execution_code(self, code):
for arg in self.args:
if arg.type.is_pyobject:
arg.generate_deletion_code(code)
elif arg.type.is_ptr and arg.type.base_type.is_cpp_class:
arg.generate_result_code(code)
code.putln("delete %s;" % arg.result())
# else error reported earlier
def annotate(self, code):
for arg in self.args:
arg.annotate(code)
class PassStatNode(StatNode):
# pass statement
child_attrs = []
def analyse_expressions(self, env):
pass
def generate_execution_code(self, code):
pass
class BreakStatNode(StatNode):
child_attrs = []
def analyse_expressions(self, env):
pass
def generate_execution_code(self, code):
if not code.break_label:
error(self.pos, "break statement not inside loop")
else:
code.put_goto(code.break_label)
class ContinueStatNode(StatNode):
child_attrs = []
def analyse_expressions(self, env):
pass
def generate_execution_code(self, code):
if code.funcstate.in_try_finally:
error(self.pos, "continue statement inside try of try...finally")
elif not code.continue_label:
error(self.pos, "continue statement not inside loop")
else:
code.put_goto(code.continue_label)
class ReturnStatNode(StatNode):
# return statement
#
# value ExprNode or None
# return_type PyrexType
child_attrs = ["value"]
def analyse_expressions(self, env):
return_type = env.return_type
self.return_type = return_type
if not return_type:
error(self.pos, "Return not inside a function body")
return
if 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")
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")
def nogil_check(self, env):
if self.return_type.is_pyobject:
self.gil_error()
gil_message = "Returning Python object"
def generate_execution_code(self, code):
code.mark_pos(self.pos)
if not self.return_type:
# error reported earlier
return
if self.return_type.is_pyobject:
code.put_xdecref(Naming.retval_cname,
self.return_type)
if self.value:
self.value.generate_evaluation_code(code)
self.value.make_owned_reference(code)
code.putln(
"%s = %s;" % (
Naming.retval_cname,
self.value.result_as(self.return_type)))
self.value.generate_post_assignment_code(code)
self.value.free_temps(code)
else:
if self.return_type.is_pyobject:
code.put_init_to_py_none(Naming.retval_cname, self.return_type)
elif self.return_type.is_returncode:
code.putln(
"%s = %s;" % (
Naming.retval_cname,
self.return_type.default_value))
for cname, type in code.funcstate.temps_holding_reference():
code.put_decref_clear(cname, type)
code.put_goto(code.return_label)
def generate_function_definitions(self, env, code):
if self.value is not None:
self.value.generate_function_definitions(env, code)
def annotate(self, code):
if self.value:
self.value.annotate(code)
class RaiseStatNode(StatNode):
# raise statement
#
# exc_type ExprNode or None
# exc_value ExprNode or None
# exc_tb ExprNode or None
child_attrs = ["exc_type", "exc_value", "exc_tb"]
def analyse_expressions(self, env):
if self.exc_type:
self.exc_type.analyse_types(env)
self.exc_type = self.exc_type.coerce_to_pyobject(env)
if self.exc_value:
self.exc_value.analyse_types(env)
self.exc_value = self.exc_value.coerce_to_pyobject(env)
if self.exc_tb:
self.exc_tb.analyse_types(env)
self.exc_tb = self.exc_tb.coerce_to_pyobject(env)
env.use_utility_code(raise_utility_code)
nogil_check = Node.gil_error
gil_message = "Raising exception"
def generate_execution_code(self, code):
if self.exc_type:
self.exc_type.generate_evaluation_code(code)
type_code = self.exc_type.py_result()
else:
type_code = "0"
if self.exc_value:
self.exc_value.generate_evaluation_code(code)
value_code = self.exc_value.py_result()
else:
value_code = "0"
if self.exc_tb:
self.exc_tb.generate_evaluation_code(code)
tb_code = self.exc_tb.py_result()
else:
tb_code = "0"
code.putln(
"__Pyx_Raise(%s, %s, %s);" % (
type_code,
value_code,
tb_code))
for obj in (self.exc_type, self.exc_value, self.exc_tb):
if obj:
obj.generate_disposal_code(code)
obj.free_temps(code)
code.putln(
code.error_goto(self.pos))
def generate_function_definitions(self, env, code):
if self.exc_type is not None:
self.exc_type.generate_function_definitions(env, code)
if self.exc_value is not None:
self.exc_value.generate_function_definitions(env, code)
if self.exc_tb is not None:
self.exc_tb.generate_function_definitions(env, code)
def annotate(self, code):
if self.exc_type:
self.exc_type.annotate(code)
if self.exc_value:
self.exc_value.annotate(code)
if self.exc_tb:
self.exc_tb.annotate(code)
class ReraiseStatNode(StatNode):
child_attrs = []
def analyse_expressions(self, env):
env.use_utility_code(restore_exception_utility_code)
nogil_check = Node.gil_error
gil_message = "Raising exception"
def generate_execution_code(self, code):
vars = code.funcstate.exc_vars
if vars:
for varname in vars:
code.put_giveref(varname)
code.putln("__Pyx_ErrRestore(%s, %s, %s);" % tuple(vars))
for varname in vars:
code.put("%s = 0; " % varname)
code.putln()
code.putln(code.error_goto(self.pos))
else:
error(self.pos, "Reraise not inside except clause")
class AssertStatNode(StatNode):
# assert statement
#
# cond ExprNode
# value ExprNode or None
child_attrs = ["cond", "value"]
def analyse_expressions(self, env):
self.cond = self.cond.analyse_boolean_expression(env)
if self.value:
self.value.analyse_types(env)
self.value = self.value.coerce_to_pyobject(env)
nogil_check = Node.gil_error
gil_message = "Raising exception"
def generate_execution_code(self, code):
code.putln("#ifndef PYREX_WITHOUT_ASSERTIONS")
self.cond.generate_evaluation_code(code)
code.putln(
"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())
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.putln(
"}")
self.cond.generate_disposal_code(code)
self.cond.free_temps(code)
code.putln("#endif")
def generate_function_definitions(self, env, code):
self.cond.generate_function_definitions(env, code)
if self.value is not None:
self.value.generate_function_definitions(env, code)
def annotate(self, code):
self.cond.annotate(code)
if self.value:
self.value.annotate(code)
class IfStatNode(StatNode):
# if statement
#
# if_clauses [IfClauseNode]
# else_clause StatNode or None
child_attrs = ["if_clauses", "else_clause"]
def analyse_control_flow(self, env):
env.start_branching(self.pos)
for if_clause in self.if_clauses:
if_clause.analyse_control_flow(env)
env.next_branch(if_clause.end_pos())
if self.else_clause:
self.else_clause.analyse_control_flow(env)
env.finish_branching(self.end_pos())
def analyse_declarations(self, env):
for if_clause in self.if_clauses:
if_clause.analyse_declarations(env)
if self.else_clause:
self.else_clause.analyse_declarations(env)
def analyse_expressions(self, env):
for if_clause in self.if_clauses:
if_clause.analyse_expressions(env)
if self.else_clause:
self.else_clause.analyse_expressions(env)
def generate_execution_code(self, code):
code.mark_pos(self.pos)
end_label = code.new_label()
for if_clause in self.if_clauses:
if_clause.generate_execution_code(code, end_label)
if self.else_clause:
code.putln("/*else*/ {")
self.else_clause.generate_execution_code(code)
code.putln("}")
code.put_label(end_label)
def generate_function_definitions(self, env, code):
for clause in self.if_clauses:
clause.generate_function_definitions(env, code)
if self.else_clause is not None:
self.else_clause.generate_function_definitions(env, code)
def annotate(self, code):
for if_clause in self.if_clauses:
if_clause.annotate(code)
if self.else_clause:
self.else_clause.annotate(code)
class IfClauseNode(Node):
# if or elif clause in an if statement
#
# condition ExprNode
# body StatNode
child_attrs = ["condition", "body"]
def analyse_control_flow(self, env):
self.body.analyse_control_flow(env)
def analyse_declarations(self, env):
self.condition.analyse_declarations(env)
self.body.analyse_declarations(env)
def analyse_expressions(self, env):
self.condition = \
self.condition.analyse_temp_boolean_expression(env)
self.body.analyse_expressions(env)
def get_constant_condition_result(self):
if self.condition.has_constant_result():
return bool(self.condition.constant_result)
else:
return None
def generate_execution_code(self, code, end_label):
self.condition.generate_evaluation_code(code)
code.putln(
"if (%s) {" %
self.condition.result())
self.condition.generate_disposal_code(code)
self.condition.free_temps(code)
self.body.generate_execution_code(code)
code.put_goto(end_label)
code.putln("}")
def generate_function_definitions(self, env, code):
self.condition.generate_function_definitions(env, code)
self.body.generate_function_definitions(env, code)
def annotate(self, code):
self.condition.annotate(code)
self.body.annotate(code)
class SwitchCaseNode(StatNode):
# Generated in the optimization of an if-elif-else node
#
# conditions [ExprNode]
# body StatNode
child_attrs = ['conditions', 'body']
def generate_execution_code(self, code):
for cond in self.conditions:
code.mark_pos(cond.pos)
cond.generate_evaluation_code(code)
code.putln("case %s:" % cond.result())
self.body.generate_execution_code(code)
code.putln("break;")
def generate_function_definitions(self, env, code):
for cond in self.conditions:
cond.generate_function_definitions(env, code)
self.body.generate_function_definitions(env, code)
def annotate(self, code):
for cond in self.conditions:
cond.annotate(code)
self.body.annotate(code)
class SwitchStatNode(StatNode):
# Generated in the optimization of an if-elif-else node
#
# test ExprNode
# cases [SwitchCaseNode]
# else_clause StatNode or None
child_attrs = ['test', 'cases', 'else_clause']
def generate_execution_code(self, code):
code.putln("switch (%s) {" % self.test.result())
for case in self.cases:
case.generate_execution_code(code)
if self.else_clause is not None:
code.putln("default:")
self.else_clause.generate_execution_code(code)
code.putln("break;")
code.putln("}")
def generate_function_definitions(self, env, code):
self.test.generate_function_definitions(env, code)
for case in self.cases:
case.generate_function_definitions(env, code)
if self.else_clause is not None:
self.else_clause.generate_function_definitions(env, code)
def annotate(self, code):
self.test.annotate(code)
for case in self.cases:
case.annotate(code)
if self.else_clause is not None:
self.else_clause.annotate(code)
class LoopNode(object):
def analyse_control_flow(self, env):
env.start_branching(self.pos)
self.body.analyse_control_flow(env)
env.next_branch(self.body.end_pos())
if self.else_clause:
self.else_clause.analyse_control_flow(env)
env.finish_branching(self.end_pos())
class WhileStatNode(LoopNode, StatNode):
# while statement
#
# condition ExprNode
# body StatNode
# else_clause StatNode
child_attrs = ["condition", "body", "else_clause"]
def analyse_declarations(self, env):
self.body.analyse_declarations(env)
if self.else_clause:
self.else_clause.analyse_declarations(env)
def analyse_expressions(self, env):
self.condition = \
self.condition.analyse_temp_boolean_expression(env)
self.body.analyse_expressions(env)
if self.else_clause:
self.else_clause.analyse_expressions(env)
def generate_execution_code(self, code):
old_loop_labels = code.new_loop_labels()
code.putln(
"while (1) {")
self.condition.generate_evaluation_code(code)
self.condition.generate_disposal_code(code)
code.putln(
"if (!%s) break;" %
self.condition.result())
self.condition.free_temps(code)
self.body.generate_execution_code(code)
code.put_label(code.continue_label)
code.putln("}")
break_label = code.break_label
code.set_loop_labels(old_loop_labels)
if self.else_clause:
code.putln("/*else*/ {")
self.else_clause.generate_execution_code(code)
code.putln("}")
code.put_label(break_label)
def generate_function_definitions(self, env, code):
self.condition.generate_function_definitions(env, code)
self.body.generate_function_definitions(env, code)
if self.else_clause is not None:
self.else_clause.generate_function_definitions(env, code)
def annotate(self, code):
self.condition.annotate(code)
self.body.annotate(code)
if self.else_clause:
self.else_clause.annotate(code)
def ForStatNode(pos, **kw):
if 'iterator' in kw:
return ForInStatNode(pos, **kw)
else:
return ForFromStatNode(pos, **kw)
class ForInStatNode(LoopNode, StatNode):
# for statement
#
# target ExprNode
# iterator IteratorNode
# body StatNode
# else_clause StatNode
# item NextNode used internally
child_attrs = ["target", "iterator", "body", "else_clause"]
item = None
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)
def analyse_expressions(self, env):
import ExprNodes
self.target.analyse_target_types(env)
self.iterator.analyse_expressions(env)
self.item = ExprNodes.NextNode(self.iterator, env)
self.item = self.item.coerce_to(self.target.type, env)
self.body.analyse_expressions(env)
if self.else_clause:
self.else_clause.analyse_expressions(env)
def generate_execution_code(self, code):
old_loop_labels = code.new_loop_labels()
self.iterator.allocate_counter_temp(code)
self.iterator.generate_evaluation_code(code)
code.putln(
"for (;;) {")
self.item.generate_evaluation_code(code)
self.target.generate_assignment_code(self.item, code)
self.body.generate_execution_code(code)
code.put_label(code.continue_label)
code.putln(
"}")
break_label = code.break_label
code.set_loop_labels(old_loop_labels)
if self.else_clause:
# in nested loops, the 'else' block can contain a
# 'continue' statement for the outer loop, but we may need
# to generate cleanup code before taking that path, so we
# intercept it here
orig_continue_label = code.continue_label
code.continue_label = code.new_label('outer_continue')
code.putln("/*else*/ {")
self.else_clause.generate_execution_code(code)
code.putln("}")
if code.label_used(code.continue_label):
code.put_goto(break_label)
code.put_label(code.continue_label)
self.iterator.generate_disposal_code(code)
code.put_goto(orig_continue_label)
code.set_loop_labels(old_loop_labels)
if code.label_used(break_label):
code.put_label(break_label)
self.iterator.release_counter_temp(code)
self.iterator.generate_disposal_code(code)
self.iterator.free_temps(code)
def generate_function_definitions(self, env, code):
self.target.generate_function_definitions(env, code)
self.iterator.generate_function_definitions(env, code)
self.body.generate_function_definitions(env, code)
if self.else_clause is not None:
self.else_clause.generate_function_definitions(env, code)
def annotate(self, code):
self.target.annotate(code)
self.iterator.annotate(code)
self.body.annotate(code)
if self.else_clause:
self.else_clause.annotate(code)
self.item.annotate(code)
class ForFromStatNode(LoopNode, StatNode):
# for name from expr rel name rel expr
#
# target NameNode
# bound1 ExprNode
# relation1 string
# relation2 string
# bound2 ExprNode
# step ExprNode or None
# body StatNode
# else_clause StatNode or None
#
# Used internally:
#
# from_range bool
# is_py_target bool
# loopvar_node ExprNode (usually a NameNode or temp node)
# py_loopvar_node PyTempNode or None
child_attrs = ["target", "bound1", "bound2", "step", "body", "else_clause"]
is_py_target = False
loopvar_node = None
py_loopvar_node = None
from_range = False
gil_message = "For-loop using object bounds or target"
def nogil_check(self, env):
for x in (self.target, self.bound1, self.bound2):
if x.type.is_pyobject:
self.gil_error()
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)
def analyse_expressions(self, env):
import ExprNodes
self.target.analyse_target_types(env)
self.bound1.analyse_types(env)
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 statment. Consider switching the directions of the relations.", 2)
self.step.analyse_types(env)
target_type = self.target.type
if self.target.type.is_numeric:
loop_type = self.target.type
else:
loop_type = PyrexTypes.c_int_type
if not self.bound1.type.is_pyobject:
loop_type = PyrexTypes.widest_numeric_type(loop_type, self.bound1.type)
if not self.bound2.type.is_pyobject:
loop_type = PyrexTypes.widest_numeric_type(loop_type, self.bound2.type)
if self.step is not None and not self.step.type.is_pyobject:
loop_type = PyrexTypes.widest_numeric_type(loop_type, self.step.type)
self.bound1 = self.bound1.coerce_to(loop_type, env)
self.bound2 = self.bound2.coerce_to(loop_type, env)
if not self.bound2.is_literal:
self.bound2 = self.bound2.coerce_to_temp(env)
if self.step is not None:
self.step = self.step.coerce_to(loop_type, env)
if not self.step.is_literal:
self.step = self.step.coerce_to_temp(env)
target_type = self.target.type
if not (target_type.is_pyobject or target_type.is_numeric):
error(self.target.pos,
"for-from loop variable must be c numeric type or Python object")
if target_type.is_numeric:
self.is_py_target = False
if isinstance(self.target, ExprNodes.IndexNode) and self.target.is_buffer_access:
raise error(self.pos, "Buffer indexing not allowed as for loop target.")
self.loopvar_node = self.target
self.py_loopvar_node = None
else:
self.is_py_target = True
c_loopvar_node = ExprNodes.TempNode(self.pos, loop_type, env)
self.loopvar_node = c_loopvar_node
self.py_loopvar_node = \
ExprNodes.CloneNode(c_loopvar_node).coerce_to_pyobject(env)
self.body.analyse_expressions(env)
if self.else_clause:
self.else_clause.analyse_expressions(env)
def generate_execution_code(self, code):
old_loop_labels = code.new_loop_labels()
from_range = self.from_range
self.bound1.generate_evaluation_code(code)
self.bound2.generate_evaluation_code(code)
offset, incop = self.relation_table[self.relation1]
if self.step is not None:
self.step.generate_evaluation_code(code)
step = self.step.result()
incop = "%s=%s" % (incop[0], step)
import ExprNodes
if isinstance(self.loopvar_node, ExprNodes.TempNode):
self.loopvar_node.allocate(code)
if isinstance(self.py_loopvar_node, ExprNodes.TempNode):
self.py_loopvar_node.allocate(code)
if from_range:
loopvar_name = code.funcstate.allocate_temp(self.target.type, False)
else:
loopvar_name = self.loopvar_node.result()
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))
if self.py_loopvar_node:
self.py_loopvar_node.generate_evaluation_code(code)
self.target.generate_assignment_code(self.py_loopvar_node, code)
elif from_range:
code.putln("%s = %s;" % (
self.target.result(), loopvar_name))
self.body.generate_execution_code(code)
code.put_label(code.continue_label)
if self.py_loopvar_node:
# This mess is to make for..from loops with python targets behave
# exactly like those with C targets with regards to re-assignment
# of the loop variable.
import ExprNodes
if self.target.entry.is_pyglobal:
# We know target is a NameNode, this is the only ugly case.
target_node = ExprNodes.PyTempNode(self.target.pos, None)
target_node.allocate(code)
interned_cname = code.intern_identifier(self.target.entry.name)
code.globalstate.use_utility_code(ExprNodes.get_name_interned_utility_code)
code.putln("%s = __Pyx_GetName(%s, %s); %s" % (
target_node.result(),
Naming.module_cname,
interned_cname,
code.error_goto_if_null(target_node.result(), self.target.pos)))
code.put_gotref(target_node.result())
else:
target_node = self.target
from_py_node = ExprNodes.CoerceFromPyTypeNode(self.loopvar_node.type, target_node, None)
from_py_node.temp_code = loopvar_name
from_py_node.generate_result_code(code)
if self.target.entry.is_pyglobal:
code.put_decref(target_node.result(), target_node.type)
target_node.release(code)
code.putln("}")
if self.py_loopvar_node:
# This is potentially wasteful, but we don't want the semantics to
# depend on whether or not the loop is a python type.
self.py_loopvar_node.generate_evaluation_code(code)
self.target.generate_assignment_code(self.py_loopvar_node, code)
if from_range:
code.funcstate.release_temp(loopvar_name)
break_label = code.break_label
code.set_loop_labels(old_loop_labels)
if self.else_clause:
code.putln("/*else*/ {")
self.else_clause.generate_execution_code(code)
code.putln("}")
code.put_label(break_label)
self.bound1.generate_disposal_code(code)
self.bound1.free_temps(code)
self.bound2.generate_disposal_code(code)
self.bound2.free_temps(code)
if isinstance(self.loopvar_node, ExprNodes.TempNode):
self.loopvar_node.release(code)
if isinstance(self.py_loopvar_node, ExprNodes.TempNode):
self.py_loopvar_node.release(code)
if self.step is not None:
self.step.generate_disposal_code(code)
self.step.free_temps(code)
relation_table = {
# {relop : (initial offset, increment op)}
'<=': ("", "++"),
'<' : ("+1", "++"),
'>=': ("", "--"),
'>' : ("-1", "--")
}
def generate_function_definitions(self, env, code):
self.target.generate_function_definitions(env, code)
self.bound1.generate_function_definitions(env, code)
self.bound2.generate_function_definitions(env, code)
if self.step is not None:
self.step.generate_function_definitions(env, code)
self.body.generate_function_definitions(env, code)
if self.else_clause is not None:
self.else_clause.generate_function_definitions(env, code)
def annotate(self, code):
self.target.annotate(code)
self.bound1.annotate(code)
self.bound2.annotate(code)
if self.step:
self.step.annotate(code)
self.body.annotate(code)
if self.else_clause:
self.else_clause.annotate(code)
class WithStatNode(StatNode):
"""
Represents a Python with statement.
This is only used at parse tree level; and is not present in
analysis or generation phases.
"""
# manager The with statement manager object
# target Node (lhs expression)
# body StatNode
child_attrs = ["manager", "target", "body"]
class TryExceptStatNode(StatNode):
# try .. except statement
#
# body StatNode
# except_clauses [ExceptClauseNode]
# else_clause StatNode or None
child_attrs = ["body", "except_clauses", "else_clause"]
def analyse_control_flow(self, env):
env.start_branching(self.pos)
self.body.analyse_control_flow(env)
successful_try = env.control_flow # grab this for later
env.next_branch(self.body.end_pos())
env.finish_branching(self.body.end_pos())
env.start_branching(self.except_clauses[0].pos)
for except_clause in self.except_clauses:
except_clause.analyse_control_flow(env)
env.next_branch(except_clause.end_pos())
# the else cause it executed only when the try clause finishes
env.control_flow.incoming = successful_try
if self.else_clause:
self.else_clause.analyse_control_flow(env)
env.finish_branching(self.end_pos())
def analyse_declarations(self, env):
self.body.analyse_declarations(env)
for except_clause in self.except_clauses:
except_clause.analyse_declarations(env)
if self.else_clause:
self.else_clause.analyse_declarations(env)
env.use_utility_code(reset_exception_utility_code)
def analyse_expressions(self, env):
self.body.analyse_expressions(env)
default_clause_seen = 0
for except_clause in self.except_clauses:
except_clause.analyse_expressions(env)
if default_clause_seen:
error(except_clause.pos, "default 'except:' must be last")
if not except_clause.pattern:
default_clause_seen = 1
self.has_default_clause = default_clause_seen
if self.else_clause:
self.else_clause.analyse_expressions(env)
nogil_check = Node.gil_error
gil_message = "Try-except statement"
def generate_execution_code(self, code):
old_return_label = code.return_label
old_break_label = code.break_label
old_continue_label = code.continue_label
old_error_label = code.new_error_label()
our_error_label = code.error_label
except_end_label = code.new_label('exception_handled')
except_error_label = code.new_label('except_error')
except_return_label = code.new_label('except_return')
try_return_label = code.new_label('try_return')
try_break_label = code.new_label('try_break')
try_continue_label = code.new_label('try_continue')
try_end_label = code.new_label('try_end')
code.putln("{")
code.putln("PyObject %s;" %
', '.join(['*%s' % var for var in Naming.exc_save_vars]))
code.putln("__Pyx_ExceptionSave(%s);" %
', '.join(['&%s' % var for var in Naming.exc_save_vars]))
for var in Naming.exc_save_vars:
code.put_xgotref(var)
code.putln(
"/*try:*/ {")
code.return_label = try_return_label
code.break_label = try_break_label
code.continue_label = try_continue_label
self.body.generate_execution_code(code)
code.putln(
"}")
temps_to_clean_up = code.funcstate.all_free_managed_temps()
code.error_label = except_error_label
code.return_label = except_return_label
if self.else_clause:
code.putln(
"/*else:*/ {")
self.else_clause.generate_execution_code(code)
code.putln(
"}")
for var in Naming.exc_save_vars:
code.put_xdecref_clear(var, py_object_type)
code.put_goto(try_end_label)
if code.label_used(try_return_label):
code.put_label(try_return_label)
for var in Naming.exc_save_vars: code.put_xgiveref(var)
code.putln("__Pyx_ExceptionReset(%s);" %
', '.join(Naming.exc_save_vars))
code.put_goto(old_return_label)
code.put_label(our_error_label)
for temp_name, type in temps_to_clean_up:
code.put_xdecref_clear(temp_name, type)
for except_clause in self.except_clauses:
except_clause.generate_handling_code(code, except_end_label)
error_label_used = code.label_used(except_error_label)
if error_label_used or not self.has_default_clause:
if error_label_used:
code.put_label(except_error_label)
for var in Naming.exc_save_vars: code.put_xgiveref(var)
code.putln("__Pyx_ExceptionReset(%s);" %
', '.join(Naming.exc_save_vars))
code.put_goto(old_error_label)
for exit_label, old_label in zip(
[try_break_label, try_continue_label, except_return_label],
[old_break_label, old_continue_label, old_return_label]):
if code.label_used(exit_label):
code.put_label(exit_label)
for var in Naming.exc_save_vars: code.put_xgiveref(var)
code.putln("__Pyx_ExceptionReset(%s);" %
', '.join(Naming.exc_save_vars))
code.put_goto(old_label)
if code.label_used(except_end_label):
code.put_label(except_end_label)
for var in Naming.exc_save_vars: code.put_xgiveref(var)
code.putln("__Pyx_ExceptionReset(%s);" %
', '.join(Naming.exc_save_vars))
code.put_label(try_end_label)
code.putln("}")
code.return_label = old_return_label
code.break_label = old_break_label
code.continue_label = old_continue_label
code.error_label = old_error_label
def generate_function_definitions(self, env, code):
self.body.generate_function_definitions(env, code)
for except_clause in self.except_clauses:
except_clause.generate_function_definitions(env, code)
if self.else_clause is not None:
self.else_clause.generate_function_definitions(env, code)
def annotate(self, code):
self.body.annotate(code)
for except_node in self.except_clauses:
except_node.annotate(code)
if self.else_clause:
self.else_clause.annotate(code)
class ExceptClauseNode(Node):
# Part of try ... except statement.
#
# pattern [ExprNode]
# target ExprNode or None
# body StatNode
# excinfo_target NameNode or None optional target for exception info
# match_flag string result of exception match
# exc_value ExcValueNode used internally
# function_name string qualified name of enclosing function
# exc_vars (string * 3) local exception variables
# excinfo_target is never set by the parser, but can be set by a transform
# in order to extract more extensive information about the exception as a
# sys.exc_info()-style tuple into a target variable
child_attrs = ["pattern", "target", "body", "exc_value", "excinfo_target"]
exc_value = None
excinfo_target = None
def analyse_declarations(self, env):
if self.target:
self.target.analyse_target_declaration(env)
if self.excinfo_target is not None:
self.excinfo_target.analyse_target_declaration(env)
self.body.analyse_declarations(env)
def analyse_expressions(self, env):
import ExprNodes
genv = env.global_scope()
self.function_name = env.qualified_name
if self.pattern:
# normalise/unpack self.pattern into a list
for i, pattern in enumerate(self.pattern):
pattern.analyse_expressions(env)
self.pattern[i] = pattern.coerce_to_pyobject(env)
if self.target:
self.exc_value = ExprNodes.ExcValueNode(self.pos, env)
self.target.analyse_target_expression(env, self.exc_value)
if self.excinfo_target is not None:
import ExprNodes
self.excinfo_tuple = ExprNodes.TupleNode(pos=self.pos, args=[
ExprNodes.ExcValueNode(pos=self.pos, env=env) for x in range(3)])
self.excinfo_tuple.analyse_expressions(env)
self.excinfo_target.analyse_target_expression(env, self.excinfo_tuple)
self.body.analyse_expressions(env)
def generate_handling_code(self, code, end_label):
code.mark_pos(self.pos)
if self.pattern:
exc_tests = []
for pattern in self.pattern:
pattern.generate_evaluation_code(code)
exc_tests.append("PyErr_ExceptionMatches(%s)" % pattern.py_result())
match_flag = code.funcstate.allocate_temp(PyrexTypes.c_int_type, False)
code.putln(
"%s = %s;" % (match_flag, ' || '.join(exc_tests)))
for pattern in self.pattern:
pattern.generate_disposal_code(code)
pattern.free_temps(code)
code.putln(
"if (%s) {" %
match_flag)
code.funcstate.release_temp(match_flag)
else:
code.putln("/*except:*/ {")
if not getattr(self.body, 'stats', True) and \
self.excinfo_target is None and self.target is None:
# most simple case: no exception variable, empty body (pass)
# => reset the exception state, done
code.putln("PyErr_Restore(0,0,0);")
code.put_goto(end_label)
code.putln("}")
return
exc_vars = [code.funcstate.allocate_temp(py_object_type,
manage_ref=True)
for i in xrange(3)]
code.putln('__Pyx_AddTraceback("%s");' % 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)))
for x in exc_vars:
code.put_gotref(x)
if self.target:
self.exc_value.set_var(exc_vars[1])
self.exc_value.generate_evaluation_code(code)
self.target.generate_assignment_code(self.exc_value, code)
if self.excinfo_target is not None:
for tempvar, node in zip(exc_vars, self.excinfo_tuple.args):
node.set_var(tempvar)
self.excinfo_tuple.generate_evaluation_code(code)
self.excinfo_target.generate_assignment_code(self.excinfo_tuple, code)
old_break_label, old_continue_label = code.break_label, code.continue_label
code.break_label = code.new_label('except_break')
code.continue_label = code.new_label('except_continue')
old_exc_vars = code.funcstate.exc_vars
code.funcstate.exc_vars = exc_vars
self.body.generate_execution_code(code)
code.funcstate.exc_vars = old_exc_vars
for var in exc_vars:
code.putln("__Pyx_DECREF(%s); %s = 0;" % (var, var))
code.put_goto(end_label)
if code.label_used(code.break_label):
code.put_label(code.break_label)
for var in exc_vars:
code.putln("__Pyx_DECREF(%s); %s = 0;" % (var, var))
code.put_goto(old_break_label)
code.break_label = old_break_label
if code.label_used(code.continue_label):
code.put_label(code.continue_label)
for var in exc_vars:
code.putln("__Pyx_DECREF(%s); %s = 0;" % (var, var))
code.put_goto(old_continue_label)
code.continue_label = old_continue_label
for temp in exc_vars:
code.funcstate.release_temp(temp)
code.putln(
"}")
def generate_function_definitions(self, env, code):
if self.target is not None:
self.target.generate_function_definitions(env, code)
self.body.generate_function_definitions(env, code)
def annotate(self, code):
if self.pattern:
for pattern in self.pattern:
pattern.annotate(code)
if self.target:
self.target.annotate(code)
self.body.annotate(code)
class TryFinallyStatNode(StatNode):
# try ... finally statement
#
# body StatNode
# finally_clause StatNode
#
# The plan is that we funnel all continue, break
# return and error gotos into the beginning of the
# finally block, setting a variable to remember which
# one we're doing. At the end of the finally block, we
# switch on the variable to figure out where to go.
# 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"]
preserve_exception = 1
disallow_continue_in_try_finally = 0
# There doesn't seem to be any point in disallowing
# continue in the try block, since we have no problem
# handling it.
def create_analysed(pos, env, body, finally_clause):
node = TryFinallyStatNode(pos, body=body, finally_clause=finally_clause)
return node
create_analysed = staticmethod(create_analysed)
def analyse_control_flow(self, env):
env.start_branching(self.pos)
self.body.analyse_control_flow(env)
env.next_branch(self.body.end_pos())
env.finish_branching(self.body.end_pos())
self.finally_clause.analyse_control_flow(env)
def analyse_declarations(self, env):
self.body.analyse_declarations(env)
self.finally_clause.analyse_declarations(env)
def analyse_expressions(self, env):
self.body.analyse_expressions(env)
self.finally_clause.analyse_expressions(env)
nogil_check = Node.gil_error
gil_message = "Try-finally statement"
def generate_execution_code(self, code):
old_error_label = code.error_label
old_labels = code.all_new_labels()
new_labels = code.get_all_labels()
new_error_label = code.error_label
catch_label = code.new_label()
code.putln(
"/*try:*/ {")
if self.disallow_continue_in_try_finally:
was_in_try_finally = code.funcstate.in_try_finally
code.funcstate.in_try_finally = 1
self.body.generate_execution_code(code)
if self.disallow_continue_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:*/ {")
cases_used = []
error_label_used = 0
for i, new_label in enumerate(new_labels):
if new_label in code.labels_used:
cases_used.append(i)
if new_label == new_error_label:
error_label_used = 1
error_label_case = i
if cases_used:
code.putln(
"int __pyx_why;")
if error_label_used and self.preserve_exception:
code.putln(
"PyObject *%s, *%s, *%s;" % Naming.exc_vars)
code.putln(
"int %s;" % Naming.exc_lineno_name)
exc_var_init_zero = ''.join(["%s = 0; " % var for var in Naming.exc_vars])
exc_var_init_zero += '%s = 0;' % Naming.exc_lineno_name
code.putln(exc_var_init_zero)
else:
exc_var_init_zero = None
code.use_label(catch_label)
code.putln(
"__pyx_why = 0; goto %s;" % catch_label)
for i in cases_used:
new_label = new_labels[i]
#if new_label and new_label != "":
if new_label == new_error_label and self.preserve_exception:
self.put_error_catcher(code,
new_error_label, i+1, catch_label, temps_to_clean_up)
else:
code.put('%s: ' % new_label)
if exc_var_init_zero:
code.putln(exc_var_init_zero)
code.putln("__pyx_why = %s; goto %s;" % (
i+1,
catch_label))
code.put_label(catch_label)
code.set_all_labels(old_labels)
if error_label_used:
code.new_error_label()
finally_error_label = code.error_label
self.finally_clause.generate_execution_code(code)
if error_label_used:
if finally_error_label in code.labels_used and self.preserve_exception:
over_label = code.new_label()
code.put_goto(over_label);
code.put_label(finally_error_label)
code.putln("if (__pyx_why == %d) {" % (error_label_case + 1))
for var in Naming.exc_vars:
code.putln("Py_XDECREF(%s);" % var)
code.putln("}")
code.put_goto(old_error_label)
code.put_label(over_label)
code.error_label = old_error_label
if cases_used:
code.putln(
"switch (__pyx_why) {")
for i in cases_used:
old_label = old_labels[i]
if old_label == old_error_label and self.preserve_exception:
self.put_error_uncatcher(code, i+1, old_error_label)
else:
code.use_label(old_label)
code.putln(
"case %s: goto %s;" % (
i+1,
old_label))
code.putln(
"}")
code.putln(
"}")
def generate_function_definitions(self, env, code):
self.body.generate_function_definitions(env, code)
self.finally_clause.generate_function_definitions(env, code)
def put_error_catcher(self, code, error_label, i, catch_label, temps_to_clean_up):
code.globalstate.use_utility_code(restore_exception_utility_code)
code.putln(
"%s: {" %
error_label)
code.putln(
"__pyx_why = %s;" %
i)
for temp_name, type in temps_to_clean_up:
code.put_xdecref_clear(temp_name, type)
code.putln(
"__Pyx_ErrFetch(&%s, &%s, &%s);" %
Naming.exc_vars)
code.putln(
"%s = %s;" % (
Naming.exc_lineno_name, Naming.lineno_cname))
code.put_goto(catch_label)
code.putln("}")
def put_error_uncatcher(self, code, i, error_label):
code.globalstate.use_utility_code(restore_exception_utility_code)
code.putln(
"case %s: {" %
i)
code.putln(
"__Pyx_ErrRestore(%s, %s, %s);" %
Naming.exc_vars)
code.putln(
"%s = %s;" % (
Naming.lineno_cname, Naming.exc_lineno_name))
for var in Naming.exc_vars:
code.putln(
"%s = 0;" %
var)
code.put_goto(error_label)
code.putln(
"}")
def annotate(self, code):
self.body.annotate(code)
self.finally_clause.annotate(code)
class GILStatNode(TryFinallyStatNode):
# 'with gil' or 'with nogil' statement
#
# state string 'gil' or 'nogil'
# child_attrs = []
preserve_exception = 0
def __init__(self, pos, state, body):
self.state = state
TryFinallyStatNode.__init__(self, pos,
body = body,
finally_clause = GILExitNode(pos, state = state))
def analyse_expressions(self, env):
env.use_utility_code(force_init_threads_utility_code)
was_nogil = env.nogil
env.nogil = 1
TryFinallyStatNode.analyse_expressions(self, env)
env.nogil = was_nogil
nogil_check = None
def generate_execution_code(self, code):
code.mark_pos(self.pos)
if self.state == 'gil':
code.putln("{ PyGILState_STATE _save = PyGILState_Ensure();")
else:
code.putln("{ PyThreadState *_save;")
code.putln("Py_UNBLOCK_THREADS")
TryFinallyStatNode.generate_execution_code(self, code)
code.putln("}")
class GILExitNode(StatNode):
# Used as the 'finally' block in a GILStatNode
#
# state string 'gil' or 'nogil'
child_attrs = []
def analyse_expressions(self, env):
pass
def generate_execution_code(self, code):
if self.state == 'gil':
code.putln("PyGILState_Release();")
else:
code.putln("Py_BLOCK_THREADS")
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
child_attrs = []
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)
if "." in self.module_name:
names = [EncodedString(name) for name in self.module_name.split(".")]
top_name = names[0]
top_module_scope = env.context.find_submodule(top_name)
module_scope = top_module_scope
for name in names[1:]:
submodule_scope = module_scope.find_submodule(name)
module_scope.declare_module(name, submodule_scope, self.pos)
module_scope = submodule_scope
if self.as_name:
env.declare_module(self.as_name, module_scope, self.pos)
else:
env.declare_module(top_name, top_module_scope, self.pos)
else:
name = self.as_name or self.module_name
env.declare_module(name, module_scope, self.pos)
def analyse_expressions(self, env):
pass
def generate_execution_code(self, code):
pass
class FromCImportStatNode(StatNode):
# from ... cimport statement
#
# module_name string Qualified name of module
# imported_names [(pos, name, as_name, kind)] Names to be imported
child_attrs = []
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)
env.add_imported_module(module_scope)
for pos, name, as_name, kind in self.imported_names:
if name == "*":
for local_name, entry in module_scope.entries.items():
env.add_imported_entry(local_name, entry, pos)
else:
entry = module_scope.lookup(name)
if entry:
if kind and not self.declaration_matches(entry, kind):
entry.redeclared(pos)
else:
if kind == 'struct' or kind == 'union':
entry = module_scope.declare_struct_or_union(name,
kind = kind, scope = None, typedef_flag = 0, pos = pos)
elif kind == 'class':
entry = module_scope.declare_c_class(name, pos = pos,
module_name = self.module_name)
else:
submodule_scope = env.context.find_module(name, relative_to = module_scope, pos = self.pos)
if submodule_scope.parent_module is module_scope:
env.declare_module(as_name or name, submodule_scope, self.pos)
else:
error(pos, "Name '%s' not declared in module '%s'"
% (name, self.module_name))
if entry:
local_name = as_name or name
env.add_imported_entry(local_name, entry, pos)
def declaration_matches(self, entry, kind):
if not entry.is_type:
return 0
type = entry.type
if kind == 'class':
if not type.is_extension_type:
return 0
else:
if not type.is_struct_or_union:
return 0
if kind != type.kind:
return 0
return 1
def analyse_expressions(self, env):
pass
def generate_execution_code(self, code):
pass
class FromImportStatNode(StatNode):
# from ... import statement
#
# module ImportNode
# items [(string, NameNode)]
# interned_items [(string, NameNode, ExprNode)]
# item PyTempNode used internally
# import_star boolean used internally
child_attrs = ["module"]
import_star = 0
def analyse_declarations(self, env):
for name, target in self.items:
if name == "*":
if not env.is_module_scope:
error(self.pos, "import * only allowed at module level")
return
env.has_import_star = 1
self.import_star = 1
else:
target.analyse_target_declaration(env)
def analyse_expressions(self, env):
import ExprNodes
self.module.analyse_expressions(env)
self.item = ExprNodes.RawCNameExprNode(self.pos, py_object_type)
self.interned_items = []
for name, target in self.items:
if name == '*':
for _, entry in env.entries.items():
if not entry.is_type and entry.type.is_extension_type:
env.use_utility_code(ExprNodes.type_test_utility_code)
break
else:
entry = env.lookup(target.name)
# check whether or not entry is already cimported
if (entry.is_type and entry.type.name == name
and hasattr(entry.type, 'module_name')):
if entry.type.module_name == self.module.module_name.value:
# cimported with absolute name
continue
try:
# cimported with relative name
module = env.find_module(self.module.module_name.value,
pos=None)
if entry.type.module_name == module.qualified_name:
continue
except AttributeError:
pass
target.analyse_target_expression(env, None)
if target.type is py_object_type:
coerced_item = None
else:
coerced_item = self.item.coerce_to(target.type, env)
self.interned_items.append((name, target, coerced_item))
def generate_execution_code(self, code):
self.module.generate_evaluation_code(code)
if self.import_star:
code.putln(
'if (%s(%s) < 0) %s;' % (
Naming.import_star,
self.module.py_result(),
code.error_goto(self.pos)))
item_temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True)
self.item.set_cname(item_temp)
for name, target, coerced_item in self.interned_items:
cname = code.intern_identifier(name)
code.putln(
'%s = PyObject_GetAttr(%s, %s); %s' % (
item_temp,
self.module.py_result(),
cname,
code.error_goto_if_null(item_temp, self.pos)))
code.put_gotref(item_temp)
if coerced_item is None:
target.generate_assignment_code(self.item, code)
else:
coerced_item.allocate_temp_result(code)
coerced_item.generate_result_code(code)
target.generate_assignment_code(coerced_item, code)
code.put_decref_clear(item_temp, py_object_type)
code.funcstate.release_temp(item_temp)
self.module.generate_disposal_code(code)
self.module.free_temps(code)
#------------------------------------------------------------------------------------
#
# Runtime support code
#
#------------------------------------------------------------------------------------
utility_function_predeclarations = \
"""
/* inline attribute */
#ifndef CYTHON_INLINE
#if defined(__GNUC__)
#define CYTHON_INLINE __inline__
#elif defined(_MSC_VER)
#define CYTHON_INLINE __inline
#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#define CYTHON_INLINE inline
#else
#define CYTHON_INLINE
#endif
#endif
/* unused attribute */
#ifndef CYTHON_UNUSED
# if defined(__GNUC__)
# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
# define CYTHON_UNUSED __attribute__ ((__unused__))
# else
# define CYTHON_UNUSED
# endif
# elif defined(__ICC) || defined(__INTEL_COMPILER)
# define CYTHON_UNUSED __attribute__ ((__unused__))
# else
# define CYTHON_UNUSED
# endif
#endif
typedef struct {PyObject **p; char *s; const long n; const char* encoding; const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; /*proto*/
"""
if Options.gcc_branch_hints:
branch_prediction_macros = \
"""
#ifdef __GNUC__
/* Test for GCC > 2.95 */
#if __GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#else /* __GNUC__ > 2 ... */
#define likely(x) (x)
#define unlikely(x) (x)
#endif /* __GNUC__ > 2 ... */
#else /* __GNUC__ */
#define likely(x) (x)
#define unlikely(x) (x)
#endif /* __GNUC__ */
"""
else:
branch_prediction_macros = \
"""
#define likely(x) (x)
#define unlikely(x) (x)
"""
#get_name_predeclaration = \
#"static PyObject *__Pyx_GetName(PyObject *dict, char *name); /*proto*/"
#get_name_interned_predeclaration = \
#"static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name); /*proto*/"
#------------------------------------------------------------------------------------
printing_utility_code = UtilityCode(
proto = """
static int __Pyx_Print(PyObject*, PyObject *, int); /*proto*/
#if PY_MAJOR_VERSION >= 3
static PyObject* %s = 0;
static PyObject* %s = 0;
#endif
""" % (Naming.print_function, Naming.print_function_kwargs),
cleanup = """
#if PY_MAJOR_VERSION >= 3
Py_CLEAR(%s);
Py_CLEAR(%s);
#endif
""" % (Naming.print_function, Naming.print_function_kwargs),
impl = r"""
#if PY_MAJOR_VERSION < 3
static PyObject *__Pyx_GetStdout(void) {
PyObject *f = PySys_GetObject((char *)"stdout");
if (!f) {
PyErr_SetString(PyExc_RuntimeError, "lost sys.stdout");
}
return f;
}
static int __Pyx_Print(PyObject* f, PyObject *arg_tuple, int newline) {
PyObject* v;
int i;
if (!f) {
if (!(f = __Pyx_GetStdout()))
return -1;
}
for (i=0; i < PyTuple_GET_SIZE(arg_tuple); i++) {
if (PyFile_SoftSpace(f, 1)) {
if (PyFile_WriteString(" ", f) < 0)
return -1;
}
v = PyTuple_GET_ITEM(arg_tuple, i);
if (PyFile_WriteObject(v, f, Py_PRINT_RAW) < 0)
return -1;
if (PyString_Check(v)) {
char *s = PyString_AsString(v);
Py_ssize_t len = PyString_Size(v);
if (len > 0 &&
isspace(Py_CHARMASK(s[len-1])) &&
s[len-1] != ' ')
PyFile_SoftSpace(f, 0);
}
}
if (newline) {
if (PyFile_WriteString("\n", f) < 0)
return -1;
PyFile_SoftSpace(f, 0);
}
return 0;
}
#else /* Python 3 has a print function */
static int __Pyx_Print(PyObject* stream, PyObject *arg_tuple, int newline) {
PyObject* kwargs = 0;
PyObject* result = 0;
PyObject* end_string;
if (unlikely(!%(PRINT_FUNCTION)s)) {
%(PRINT_FUNCTION)s = __Pyx_GetAttrString(%(BUILTINS)s, "print");
if (!%(PRINT_FUNCTION)s)
return -1;
}
if (stream) {
kwargs = PyDict_New();
if (unlikely(!kwargs))
return -1;
if (unlikely(PyDict_SetItemString(kwargs, "file", stream) < 0))
goto bad;
if (!newline) {
end_string = PyUnicode_FromStringAndSize(" ", 1);
if (unlikely(!end_string))
goto bad;
if (PyDict_SetItemString(kwargs, "end", end_string) < 0) {
Py_DECREF(end_string);
goto bad;
}
Py_DECREF(end_string);
}
} else if (!newline) {
if (unlikely(!%(PRINT_KWARGS)s)) {
%(PRINT_KWARGS)s = PyDict_New();
if (unlikely(!%(PRINT_KWARGS)s))
return -1;
end_string = PyUnicode_FromStringAndSize(" ", 1);
if (unlikely(!end_string))
return -1;
if (PyDict_SetItemString(%(PRINT_KWARGS)s, "end", end_string) < 0) {
Py_DECREF(end_string);
return -1;
}
Py_DECREF(end_string);
}
kwargs = %(PRINT_KWARGS)s;
}
result = PyObject_Call(%(PRINT_FUNCTION)s, arg_tuple, kwargs);
if (unlikely(kwargs) && (kwargs != %(PRINT_KWARGS)s))
Py_DECREF(kwargs);
if (!result)
return -1;
Py_DECREF(result);
return 0;
bad:
if (kwargs != %(PRINT_KWARGS)s)
Py_XDECREF(kwargs);
return -1;
}
#endif
""" % {'BUILTINS' : Naming.builtins_cname,
'PRINT_FUNCTION' : Naming.print_function,
'PRINT_KWARGS' : Naming.print_function_kwargs}
)
printing_one_utility_code = UtilityCode(
proto = """
static int __Pyx_PrintOne(PyObject* stream, PyObject *o); /*proto*/
""",
impl = r"""
#if PY_MAJOR_VERSION < 3
static int __Pyx_PrintOne(PyObject* f, PyObject *o) {
if (!f) {
if (!(f = __Pyx_GetStdout()))
return -1;
}
if (PyFile_SoftSpace(f, 0)) {
if (PyFile_WriteString(" ", f) < 0)
return -1;
}
if (PyFile_WriteObject(o, f, Py_PRINT_RAW) < 0)
return -1;
if (PyFile_WriteString("\n", f) < 0)
return -1;
return 0;
/* the line below is just to avoid compiler
* compiler warnings about unused functions */
return __Pyx_Print(f, NULL, 0);
}
#else /* Python 3 has a print function */
static int __Pyx_PrintOne(PyObject* stream, PyObject *o) {
int res;
PyObject* arg_tuple = PyTuple_New(1);
if (unlikely(!arg_tuple))
return -1;
Py_INCREF(o);
PyTuple_SET_ITEM(arg_tuple, 0, o);
res = __Pyx_Print(stream, arg_tuple, 1);
Py_DECREF(arg_tuple);
return res;
}
#endif
""",
requires=[printing_utility_code])
#------------------------------------------------------------------------------------
# Exception raising code
#
# Exceptions are raised by __Pyx_Raise() and stored as plain
# type/value/tb in PyThreadState->curexc_*. When being caught by an
# 'except' statement, curexc_* is moved over to exc_* by
# __Pyx_GetException()
restore_exception_utility_code = UtilityCode(
proto = """
static CYTHON_INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
static CYTHON_INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
""",
impl = """
static CYTHON_INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb) {
PyObject *tmp_type, *tmp_value, *tmp_tb;
PyThreadState *tstate = PyThreadState_GET();
tmp_type = tstate->curexc_type;
tmp_value = tstate->curexc_value;
tmp_tb = tstate->curexc_traceback;
tstate->curexc_type = type;
tstate->curexc_value = value;
tstate->curexc_traceback = tb;
Py_XDECREF(tmp_type);
Py_XDECREF(tmp_value);
Py_XDECREF(tmp_tb);
}
static CYTHON_INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb) {
PyThreadState *tstate = PyThreadState_GET();
*type = tstate->curexc_type;
*value = tstate->curexc_value;
*tb = tstate->curexc_traceback;
tstate->curexc_type = 0;
tstate->curexc_value = 0;
tstate->curexc_traceback = 0;
}
""")
# The following function is based on do_raise() from ceval.c. There
# are separate versions for Python2 and Python3 as exception handling
# has changed quite a lot between the two versions.
raise_utility_code = UtilityCode(
proto = """
static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
""",
impl = """
#if PY_MAJOR_VERSION < 3
static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) {
Py_XINCREF(type);
Py_XINCREF(value);
Py_XINCREF(tb);
/* First, check the traceback argument, replacing None with NULL. */
if (tb == Py_None) {
Py_DECREF(tb);
tb = 0;
}
else if (tb != NULL && !PyTraceBack_Check(tb)) {
PyErr_SetString(PyExc_TypeError,
"raise: arg 3 must be a traceback or None");
goto raise_error;
}
/* Next, replace a missing value with None */
if (value == NULL) {
value = Py_None;
Py_INCREF(value);
}
#if PY_VERSION_HEX < 0x02050000
if (!PyClass_Check(type))
#else
if (!PyType_Check(type))
#endif
{
/* Raising an instance. The value should be a dummy. */
if (value != Py_None) {
PyErr_SetString(PyExc_TypeError,
"instance exception may not have a separate value");
goto raise_error;
}
/* Normalize to raise , */
Py_DECREF(value);
value = type;
#if PY_VERSION_HEX < 0x02050000
if (PyInstance_Check(type)) {
type = (PyObject*) ((PyInstanceObject*)type)->in_class;
Py_INCREF(type);
}
else {
type = 0;
PyErr_SetString(PyExc_TypeError,
"raise: exception must be an old-style class or instance");
goto raise_error;
}
#else
type = (PyObject*) Py_TYPE(type);
Py_INCREF(type);
if (!PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)PyExc_BaseException)) {
PyErr_SetString(PyExc_TypeError,
"raise: exception class must be a subclass of BaseException");
goto raise_error;
}
#endif
}
__Pyx_ErrRestore(type, value, tb);
return;
raise_error:
Py_XDECREF(value);
Py_XDECREF(type);
Py_XDECREF(tb);
return;
}
#else /* Python 3+ */
static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) {
if (tb == Py_None) {
tb = 0;
} else if (tb && !PyTraceBack_Check(tb)) {
PyErr_SetString(PyExc_TypeError,
"raise: arg 3 must be a traceback or None");
goto bad;
}
if (value == Py_None)
value = 0;
if (PyExceptionInstance_Check(type)) {
if (value) {
PyErr_SetString(PyExc_TypeError,
"instance exception may not have a separate value");
goto bad;
}
value = type;
type = (PyObject*) Py_TYPE(value);
} else if (!PyExceptionClass_Check(type)) {
PyErr_SetString(PyExc_TypeError,
"raise: exception class must be a subclass of BaseException");
goto bad;
}
PyErr_SetObject(type, value);
if (tb) {
PyThreadState *tstate = PyThreadState_GET();
PyObject* tmp_tb = tstate->curexc_traceback;
if (tb != tmp_tb) {
Py_INCREF(tb);
tstate->curexc_traceback = tb;
Py_XDECREF(tmp_tb);
}
}
bad:
return;
}
#endif
""",
requires=[restore_exception_utility_code])
#------------------------------------------------------------------------------------
get_exception_utility_code = UtilityCode(
proto = """
static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
""",
impl = """
static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) {
PyObject *local_type, *local_value, *local_tb;
PyObject *tmp_type, *tmp_value, *tmp_tb;
PyThreadState *tstate = PyThreadState_GET();
local_type = tstate->curexc_type;
local_value = tstate->curexc_value;
local_tb = tstate->curexc_traceback;
tstate->curexc_type = 0;
tstate->curexc_value = 0;
tstate->curexc_traceback = 0;
PyErr_NormalizeException(&local_type, &local_value, &local_tb);
if (unlikely(tstate->curexc_type))
goto bad;
#if PY_MAJOR_VERSION >= 3
if (unlikely(PyException_SetTraceback(local_value, local_tb) < 0))
goto bad;
#endif
*type = local_type;
*value = local_value;
*tb = local_tb;
Py_INCREF(local_type);
Py_INCREF(local_value);
Py_INCREF(local_tb);
tmp_type = tstate->exc_type;
tmp_value = tstate->exc_value;
tmp_tb = tstate->exc_traceback;
tstate->exc_type = local_type;
tstate->exc_value = local_value;
tstate->exc_traceback = local_tb;
/* Make sure tstate is in a consistent state when we XDECREF
these objects (XDECREF may run arbitrary code). */
Py_XDECREF(tmp_type);
Py_XDECREF(tmp_value);
Py_XDECREF(tmp_tb);
return 0;
bad:
*type = 0;
*value = 0;
*tb = 0;
Py_XDECREF(local_type);
Py_XDECREF(local_value);
Py_XDECREF(local_tb);
return -1;
}
""")
#------------------------------------------------------------------------------------
get_exception_tuple_utility_code = UtilityCode(proto="""
static PyObject *__Pyx_GetExceptionTuple(void); /*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.
impl = """
static PyObject *__Pyx_GetExceptionTuple(void) {
PyObject *type = NULL, *value = NULL, *tb = NULL;
if (__Pyx_GetException(&type, &value, &tb) == 0) {
PyObject* exc_info = PyTuple_New(3);
if (exc_info) {
Py_INCREF(type);
Py_INCREF(value);
Py_INCREF(tb);
PyTuple_SET_ITEM(exc_info, 0, type);
PyTuple_SET_ITEM(exc_info, 1, value);
PyTuple_SET_ITEM(exc_info, 2, tb);
return exc_info;
}
}
return NULL;
}
""",
requires=[get_exception_utility_code])
#------------------------------------------------------------------------------------
reset_exception_utility_code = UtilityCode(
proto = """
static CYTHON_INLINE void __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
static void __Pyx_ExceptionReset(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
""",
impl = """
static CYTHON_INLINE void __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb) {
PyThreadState *tstate = PyThreadState_GET();
*type = tstate->exc_type;
*value = tstate->exc_value;
*tb = tstate->exc_traceback;
Py_XINCREF(*type);
Py_XINCREF(*value);
Py_XINCREF(*tb);
}
static void __Pyx_ExceptionReset(PyObject *type, PyObject *value, PyObject *tb) {
PyObject *tmp_type, *tmp_value, *tmp_tb;
PyThreadState *tstate = PyThreadState_GET();
tmp_type = tstate->exc_type;
tmp_value = tstate->exc_value;
tmp_tb = tstate->exc_traceback;
tstate->exc_type = type;
tstate->exc_value = value;
tstate->exc_traceback = tb;
Py_XDECREF(tmp_type);
Py_XDECREF(tmp_value);
Py_XDECREF(tmp_tb);
}
""")
#------------------------------------------------------------------------------------
arg_type_test_utility_code = UtilityCode(
proto = """
static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed,
const char *name, int exact); /*proto*/
""",
impl = """
static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed,
const char *name, int exact)
{
if (!type) {
PyErr_Format(PyExc_SystemError, "Missing type object");
return 0;
}
if (none_allowed && obj == Py_None) return 1;
else if (exact) {
if (Py_TYPE(obj) == type) return 1;
}
else {
if (PyObject_TypeCheck(obj, type)) return 1;
}
PyErr_Format(PyExc_TypeError,
"Argument '%s' has incorrect type (expected %s, got %s)",
name, type->tp_name, Py_TYPE(obj)->tp_name);
return 0;
}
""")
#------------------------------------------------------------------------------------
#
# __Pyx_RaiseArgtupleInvalid raises the correct exception when too
# many or too few positional arguments were found. This handles
# Py_ssize_t formatting correctly.
raise_argtuple_invalid_utility_code = UtilityCode(
proto = """
static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact,
Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); /*proto*/
""",
impl = """
static void __Pyx_RaiseArgtupleInvalid(
const char* func_name,
int exact,
Py_ssize_t num_min,
Py_ssize_t num_max,
Py_ssize_t num_found)
{
Py_ssize_t num_expected;
const char *number, *more_or_less;
if (num_found < num_min) {
num_expected = num_min;
more_or_less = "at least";
} else {
num_expected = num_max;
more_or_less = "at most";
}
if (exact) {
more_or_less = "exactly";
}
number = (num_expected == 1) ? "" : "s";
PyErr_Format(PyExc_TypeError,
#if PY_VERSION_HEX < 0x02050000
"%s() takes %s %d positional argument%s (%d given)",
#else
"%s() takes %s %zd positional argument%s (%zd given)",
#endif
func_name, more_or_less, num_expected, number, num_found);
}
""")
raise_keyword_required_utility_code = UtilityCode(
proto = """
static CYTHON_INLINE void __Pyx_RaiseKeywordRequired(const char* func_name, PyObject* kw_name); /*proto*/
""",
impl = """
static CYTHON_INLINE void __Pyx_RaiseKeywordRequired(
const char* func_name,
PyObject* kw_name)
{
PyErr_Format(PyExc_TypeError,
#if PY_MAJOR_VERSION >= 3
"%s() needs keyword-only argument %U", func_name, kw_name);
#else
"%s() needs keyword-only argument %s", func_name,
PyString_AS_STRING(kw_name));
#endif
}
""")
raise_double_keywords_utility_code = UtilityCode(
proto = """
static void __Pyx_RaiseDoubleKeywordsError(
const char* func_name, PyObject* kw_name); /*proto*/
""",
impl = """
static void __Pyx_RaiseDoubleKeywordsError(
const char* func_name,
PyObject* kw_name)
{
PyErr_Format(PyExc_TypeError,
#if PY_MAJOR_VERSION >= 3
"%s() got multiple values for keyword argument '%U'", func_name, kw_name);
#else
"%s() got multiple values for keyword argument '%s'", func_name,
PyString_AS_STRING(kw_name));
#endif
}
""")
#------------------------------------------------------------------------------------
#
# __Pyx_CheckKeywordStrings raises an error if non-string keywords
# were passed to a function, or if any keywords were passed to a
# function that does not accept them.
keyword_string_check_utility_code = UtilityCode(
proto = """
static CYTHON_INLINE int __Pyx_CheckKeywordStrings(PyObject *kwdict,
const char* function_name, int kw_allowed); /*proto*/
""",
impl = """
static CYTHON_INLINE int __Pyx_CheckKeywordStrings(
PyObject *kwdict,
const char* function_name,
int kw_allowed)
{
PyObject* key = 0;
Py_ssize_t pos = 0;
while (PyDict_Next(kwdict, &pos, &key, 0)) {
#if PY_MAJOR_VERSION < 3
if (unlikely(!PyString_CheckExact(key)) && unlikely(!PyString_Check(key)))
#else
if (unlikely(!PyUnicode_CheckExact(key)) && unlikely(!PyUnicode_Check(key)))
#endif
goto invalid_keyword_type;
}
if ((!kw_allowed) && unlikely(key))
goto invalid_keyword;
return 1;
invalid_keyword_type:
PyErr_Format(PyExc_TypeError,
"%s() keywords must be strings", function_name);
return 0;
invalid_keyword:
PyErr_Format(PyExc_TypeError,
#if PY_MAJOR_VERSION < 3
"%s() got an unexpected keyword argument '%s'",
function_name, PyString_AsString(key));
#else
"%s() got an unexpected keyword argument '%U'",
function_name, key);
#endif
return 0;
}
""")
#------------------------------------------------------------------------------------
#
# __Pyx_ParseOptionalKeywords copies the optional/unknown keyword
# arguments from the kwds dict into kwds2. If kwds2 is NULL, unknown
# keywords will raise an invalid keyword error.
#
# Three kinds of errors are checked: 1) non-string keywords, 2)
# unexpected keywords and 3) overlap with positional arguments.
#
# If num_posargs is greater 0, it denotes the number of positional
# arguments that were passed and that must therefore not appear
# amongst the keywords as well.
#
# This method does not check for required keyword arguments.
#
parse_keywords_utility_code = UtilityCode(
proto = """
static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[], \
PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args, \
const char* function_name); /*proto*/
""",
impl = """
static int __Pyx_ParseOptionalKeywords(
PyObject *kwds,
PyObject **argnames[],
PyObject *kwds2,
PyObject *values[],
Py_ssize_t num_pos_args,
const char* function_name)
{
PyObject *key = 0, *value = 0;
Py_ssize_t pos = 0;
PyObject*** name;
PyObject*** first_kw_arg = argnames + num_pos_args;
while (PyDict_Next(kwds, &pos, &key, &value)) {
name = first_kw_arg;
while (*name && (**name != key)) name++;
if (*name) {
values[name-argnames] = value;
} else {
#if PY_MAJOR_VERSION < 3
if (unlikely(!PyString_CheckExact(key)) && unlikely(!PyString_Check(key))) {
#else
if (unlikely(!PyUnicode_CheckExact(key)) && unlikely(!PyUnicode_Check(key))) {
#endif
goto invalid_keyword_type;
} else {
for (name = first_kw_arg; *name; name++) {
#if PY_MAJOR_VERSION >= 3
if (PyUnicode_GET_SIZE(**name) == PyUnicode_GET_SIZE(key) &&
PyUnicode_Compare(**name, key) == 0) break;
#else
if (PyString_GET_SIZE(**name) == PyString_GET_SIZE(key) &&
_PyString_Eq(**name, key)) break;
#endif
}
if (*name) {
values[name-argnames] = value;
} else {
/* unexpected keyword found */
for (name=argnames; name != first_kw_arg; name++) {
if (**name == key) goto arg_passed_twice;
#if PY_MAJOR_VERSION >= 3
if (PyUnicode_GET_SIZE(**name) == PyUnicode_GET_SIZE(key) &&
PyUnicode_Compare(**name, key) == 0) goto arg_passed_twice;
#else
if (PyString_GET_SIZE(**name) == PyString_GET_SIZE(key) &&
_PyString_Eq(**name, key)) goto arg_passed_twice;
#endif
}
if (kwds2) {
if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad;
} else {
goto invalid_keyword;
}
}
}
}
}
return 0;
arg_passed_twice:
__Pyx_RaiseDoubleKeywordsError(function_name, **name);
goto bad;
invalid_keyword_type:
PyErr_Format(PyExc_TypeError,
"%s() keywords must be strings", function_name);
goto bad;
invalid_keyword:
PyErr_Format(PyExc_TypeError,
#if PY_MAJOR_VERSION < 3
"%s() got an unexpected keyword argument '%s'",
function_name, PyString_AsString(key));
#else
"%s() got an unexpected keyword argument '%U'",
function_name, key);
#endif
bad:
return -1;
}
""")
#------------------------------------------------------------------------------------
traceback_utility_code = UtilityCode(
proto = """
static void __Pyx_AddTraceback(const char *funcname); /*proto*/
""",
impl = """
#include "compile.h"
#include "frameobject.h"
#include "traceback.h"
static void __Pyx_AddTraceback(const char *funcname) {
PyObject *py_srcfile = 0;
PyObject *py_funcname = 0;
PyObject *py_globals = 0;
PyCodeObject *py_code = 0;
PyFrameObject *py_frame = 0;
#if PY_MAJOR_VERSION < 3
py_srcfile = PyString_FromString(%(FILENAME)s);
#else
py_srcfile = PyUnicode_FromString(%(FILENAME)s);
#endif
if (!py_srcfile) goto bad;
if (%(CLINENO)s) {
#if PY_MAJOR_VERSION < 3
py_funcname = PyString_FromFormat( "%%s (%%s:%%d)", funcname, %(CFILENAME)s, %(CLINENO)s);
#else
py_funcname = PyUnicode_FromFormat( "%%s (%%s:%%d)", funcname, %(CFILENAME)s, %(CLINENO)s);
#endif
}
else {
#if PY_MAJOR_VERSION < 3
py_funcname = PyString_FromString(funcname);
#else
py_funcname = PyUnicode_FromString(funcname);
#endif
}
if (!py_funcname) goto bad;
py_globals = PyModule_GetDict(%(GLOBALS)s);
if (!py_globals) goto bad;
py_code = PyCode_New(
0, /*int argcount,*/
#if PY_MAJOR_VERSION >= 3
0, /*int kwonlyargcount,*/
#endif
0, /*int nlocals,*/
0, /*int stacksize,*/
0, /*int flags,*/
%(EMPTY_BYTES)s, /*PyObject *code,*/
%(EMPTY_TUPLE)s, /*PyObject *consts,*/
%(EMPTY_TUPLE)s, /*PyObject *names,*/
%(EMPTY_TUPLE)s, /*PyObject *varnames,*/
%(EMPTY_TUPLE)s, /*PyObject *freevars,*/
%(EMPTY_TUPLE)s, /*PyObject *cellvars,*/
py_srcfile, /*PyObject *filename,*/
py_funcname, /*PyObject *name,*/
%(LINENO)s, /*int firstlineno,*/
%(EMPTY_BYTES)s /*PyObject *lnotab*/
);
if (!py_code) goto bad;
py_frame = PyFrame_New(
PyThreadState_GET(), /*PyThreadState *tstate,*/
py_code, /*PyCodeObject *code,*/
py_globals, /*PyObject *globals,*/
0 /*PyObject *locals*/
);
if (!py_frame) goto bad;
py_frame->f_lineno = %(LINENO)s;
PyTraceBack_Here(py_frame);
bad:
Py_XDECREF(py_srcfile);
Py_XDECREF(py_funcname);
Py_XDECREF(py_code);
Py_XDECREF(py_frame);
}
""" % {
'FILENAME': Naming.filename_cname,
'LINENO': Naming.lineno_cname,
'CFILENAME': Naming.cfilenm_cname,
'CLINENO': Naming.clineno_cname,
'GLOBALS': Naming.module_cname,
'EMPTY_TUPLE' : Naming.empty_tuple,
'EMPTY_BYTES' : Naming.empty_bytes,
})
#------------------------------------------------------------------------------------
unraisable_exception_utility_code = UtilityCode(
proto = """
static void __Pyx_WriteUnraisable(const char *name); /*proto*/
""",
impl = """
static void __Pyx_WriteUnraisable(const char *name) {
PyObject *old_exc, *old_val, *old_tb;
PyObject *ctx;
__Pyx_ErrFetch(&old_exc, &old_val, &old_tb);
#if PY_MAJOR_VERSION < 3
ctx = PyString_FromString(name);
#else
ctx = PyUnicode_FromString(name);
#endif
__Pyx_ErrRestore(old_exc, old_val, old_tb);
if (!ctx) {
PyErr_WriteUnraisable(Py_None);
} else {
PyErr_WriteUnraisable(ctx);
Py_DECREF(ctx);
}
}
""",
requires=[restore_exception_utility_code])
#------------------------------------------------------------------------------------
set_vtable_utility_code = UtilityCode(
proto = """
static int __Pyx_SetVtable(PyObject *dict, void *vtable); /*proto*/
""",
impl = """
static int __Pyx_SetVtable(PyObject *dict, void *vtable) {
#if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0)
PyObject *ob = PyCapsule_New(vtable, 0, 0);
#else
PyObject *ob = PyCObject_FromVoidPtr(vtable, 0);
#endif
if (!ob)
goto bad;
if (PyDict_SetItemString(dict, "__pyx_vtable__", ob) < 0)
goto bad;
Py_DECREF(ob);
return 0;
bad:
Py_XDECREF(ob);
return -1;
}
""")
#------------------------------------------------------------------------------------
get_vtable_utility_code = UtilityCode(
proto = """
static int __Pyx_GetVtable(PyObject *dict, void *vtabptr); /*proto*/
""",
impl = r"""
static int __Pyx_GetVtable(PyObject *dict, void *vtabptr) {
PyObject *ob = PyMapping_GetItemString(dict, (char *)"__pyx_vtable__");
if (!ob)
goto bad;
#if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0)
*(void **)vtabptr = PyCapsule_GetPointer(ob, 0);
#else
*(void **)vtabptr = PyCObject_AsVoidPtr(ob);
#endif
if (!*(void **)vtabptr)
goto bad;
Py_DECREF(ob);
return 0;
bad:
Py_XDECREF(ob);
return -1;
}
""")
#------------------------------------------------------------------------------------
init_string_tab_utility_code = UtilityCode(
proto = """
static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/
""",
impl = """
static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) {
while (t->p) {
#if PY_MAJOR_VERSION < 3
if (t->is_unicode) {
*t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL);
} else if (t->intern) {
*t->p = PyString_InternFromString(t->s);
} else {
*t->p = PyString_FromStringAndSize(t->s, t->n - 1);
}
#else /* Python 3+ has unicode identifiers */
if (t->is_unicode | t->is_str) {
if (t->intern) {
*t->p = PyUnicode_InternFromString(t->s);
} else if (t->encoding) {
*t->p = PyUnicode_Decode(t->s, t->n - 1, t->encoding, NULL);
} else {
*t->p = PyUnicode_FromStringAndSize(t->s, t->n - 1);
}
} else {
*t->p = PyBytes_FromStringAndSize(t->s, t->n - 1);
}
#endif
if (!*t->p)
return -1;
++t;
}
return 0;
}
""")
#------------------------------------------------------------------------------------
force_init_threads_utility_code = UtilityCode(
proto="""
#ifndef __PYX_FORCE_INIT_THREADS
#if PY_VERSION_HEX < 0x02040200
#define __PYX_FORCE_INIT_THREADS 1
#else
#define __PYX_FORCE_INIT_THREADS 0
#endif
#endif
""")
#------------------------------------------------------------------------------------
# Note that cPython ignores PyTrace_EXCEPTION,
# but maybe some other profilers don't.
profile_utility_code = UtilityCode(proto="""
#ifndef CYTHON_PROFILE
#define CYTHON_PROFILE 1
#endif
#ifndef CYTHON_PROFILE_REUSE_FRAME
#define CYTHON_PROFILE_REUSE_FRAME 0
#endif
#if CYTHON_PROFILE
#include "compile.h"
#include "frameobject.h"
#include "traceback.h"
#if CYTHON_PROFILE_REUSE_FRAME
#define CYTHON_FRAME_MODIFIER static
#define CYTHON_FRAME_DEL
#else
#define CYTHON_FRAME_MODIFIER
#define CYTHON_FRAME_DEL Py_DECREF(%(FRAME)s)
#endif
#define __Pyx_TraceDeclarations \\
static PyCodeObject *%(FRAME_CODE)s = NULL; \\
CYTHON_FRAME_MODIFIER PyFrameObject *%(FRAME)s = NULL; \\
int __Pyx_use_tracing = 0;
#define __Pyx_TraceCall(funcname, srcfile, firstlineno) \\
if (unlikely(PyThreadState_GET()->use_tracing && PyThreadState_GET()->c_profilefunc)) { \\
__Pyx_use_tracing = __Pyx_TraceSetupAndCall(&%(FRAME_CODE)s, &%(FRAME)s, funcname, srcfile, firstlineno); \\
}
#define __Pyx_TraceException() \\
if (unlikely(__Pyx_use_tracing( && PyThreadState_GET()->use_tracing && PyThreadState_GET()->c_profilefunc) { \\
PyObject *exc_info = __Pyx_GetExceptionTuple(); \\
if (exc_info) { \\
PyThreadState_GET()->c_profilefunc( \\
PyThreadState_GET()->c_profileobj, %(FRAME)s, PyTrace_EXCEPTION, exc_info); \\
Py_DECREF(exc_info); \\
} \\
}
#define __Pyx_TraceReturn(result) \\
if (unlikely(__Pyx_use_tracing) && PyThreadState_GET()->use_tracing && PyThreadState_GET()->c_profilefunc) { \\
PyThreadState_GET()->c_profilefunc( \\
PyThreadState_GET()->c_profileobj, %(FRAME)s, PyTrace_RETURN, (PyObject*)result); \\
CYTHON_FRAME_DEL; \\
}
static PyCodeObject *__Pyx_createFrameCodeObject(const char *funcname, const char *srcfile, int firstlineno); /*proto*/
static int __Pyx_TraceSetupAndCall(PyCodeObject** code, PyFrameObject** frame, const char *funcname, const char *srcfile, int firstlineno); /*proto*/
#else
#define __Pyx_TraceDeclarations
#define __Pyx_TraceCall(funcname, srcfile, firstlineno)
#define __Pyx_TraceException()
#define __Pyx_TraceReturn(result)
#endif /* CYTHON_PROFILE */
"""
% {
"FRAME": Naming.frame_cname,
"FRAME_CODE": Naming.frame_code_cname,
},
impl = """
#if CYTHON_PROFILE
static int __Pyx_TraceSetupAndCall(PyCodeObject** code,
PyFrameObject** frame,
const char *funcname,
const char *srcfile,
int firstlineno) {
if (*frame == NULL || !CYTHON_PROFILE_REUSE_FRAME) {
if (*code == NULL) {
*code = __Pyx_createFrameCodeObject(funcname, srcfile, firstlineno);
if (*code == NULL) return 0;
}
*frame = PyFrame_New(
PyThreadState_GET(), /*PyThreadState *tstate*/
*code, /*PyCodeObject *code*/
PyModule_GetDict(%(MODULE)s), /*PyObject *globals*/
0 /*PyObject *locals*/
);
if (*frame == NULL) return 0;
}
else {
(*frame)->f_tstate = PyThreadState_GET();
}
return PyThreadState_GET()->c_profilefunc(PyThreadState_GET()->c_profileobj, *frame, PyTrace_CALL, NULL) == 0;
}
static PyCodeObject *__Pyx_createFrameCodeObject(const char *funcname, const char *srcfile, int firstlineno) {
PyObject *py_srcfile = 0;
PyObject *py_funcname = 0;
PyCodeObject *py_code = 0;
#if PY_MAJOR_VERSION < 3
py_funcname = PyString_FromString(funcname);
py_srcfile = PyString_FromString(srcfile);
#else
py_funcname = PyUnicode_FromString(funcname);
py_srcfile = PyUnicode_FromString(srcfile);
#endif
if (!py_funcname | !py_srcfile) goto bad;
py_code = PyCode_New(
0, /*int argcount,*/
#if PY_MAJOR_VERSION >= 3
0, /*int kwonlyargcount,*/
#endif
0, /*int nlocals,*/
0, /*int stacksize,*/
0, /*int flags,*/
%(EMPTY_BYTES)s, /*PyObject *code,*/
%(EMPTY_TUPLE)s, /*PyObject *consts,*/
%(EMPTY_TUPLE)s, /*PyObject *names,*/
%(EMPTY_TUPLE)s, /*PyObject *varnames,*/
%(EMPTY_TUPLE)s, /*PyObject *freevars,*/
%(EMPTY_TUPLE)s, /*PyObject *cellvars,*/
py_srcfile, /*PyObject *filename,*/
py_funcname, /*PyObject *name,*/
firstlineno, /*int firstlineno,*/
%(EMPTY_BYTES)s /*PyObject *lnotab*/
);
bad:
Py_XDECREF(py_srcfile);
Py_XDECREF(py_funcname);
return py_code;
}
#endif /* CYTHON_PROFILE */
""" % {
'EMPTY_TUPLE' : Naming.empty_tuple,
'EMPTY_BYTES' : Naming.empty_bytes,
"MODULE": Naming.module_cname,
})
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Optimize.py 0000664 0000000 0000000 00000371341 11446142532 0025145 0 ustar 00root root 0000000 0000000 import Nodes
import ExprNodes
import PyrexTypes
import Visitor
import Builtin
import UtilNodes
import TypeSlots
import Symtab
import Options
import Naming
from Code import UtilityCode
from StringEncoding import EncodedString, BytesLiteral
from Errors import error
from ParseTreeTransforms import SkipDeclarations
import codecs
try:
reduce
except NameError:
from functools import reduce
try:
set
except NameError:
from sets import Set as set
class FakePythonEnv(object):
"A fake environment for creating type test nodes etc."
nogil = False
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)
if isinstance(a, ExprNodes.NameNode) and isinstance(b, ExprNodes.NameNode):
return a.name == b.name
if isinstance(a, ExprNodes.AttributeNode) and isinstance(b, ExprNodes.AttributeNode):
return not a.is_py_attr and is_common_value(a.obj, b.obj) and a.attribute == b.attribute
return False
class IterationTransform(Visitor.VisitorTransform):
"""Transform some common for-in loop patterns into efficient C loops:
- for-in-dict loop becomes a while loop calling PyDict_Next()
- for-in-enumerate is replaced by an external counter variable
- for-in-range loop becomes a plain C for loop
"""
PyDict_Next_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_bint_type, [
PyrexTypes.CFuncTypeArg("dict", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("pos", PyrexTypes.c_py_ssize_t_ptr_type, None),
PyrexTypes.CFuncTypeArg("key", PyrexTypes.CPtrType(PyrexTypes.py_object_type), None),
PyrexTypes.CFuncTypeArg("value", PyrexTypes.CPtrType(PyrexTypes.py_object_type), None)
])
PyDict_Next_name = EncodedString("PyDict_Next")
PyDict_Next_entry = Symtab.Entry(
PyDict_Next_name, PyDict_Next_name, PyDict_Next_func_type)
visit_Node = Visitor.VisitorTransform.recurse_to_children
def visit_ModuleNode(self, node):
self.current_scope = node.scope
self.visitchildren(node)
return node
def visit_DefNode(self, node):
oldscope = self.current_scope
self.current_scope = node.entry.scope
self.visitchildren(node)
self.current_scope = oldscope
return node
def visit_PrimaryCmpNode(self, node):
if node.is_ptr_contains():
# for t in operand2:
# if operand1 == t:
# res = True
# break
# else:
# res = False
pos = node.pos
res_handle = UtilNodes.TempHandle(PyrexTypes.c_bint_type)
res = res_handle.ref(pos)
result_ref = UtilNodes.ResultRefNode(node)
if isinstance(node.operand2, ExprNodes.IndexNode):
base_type = node.operand2.base.type.base_type
else:
base_type = node.operand2.type.base_type
target_handle = UtilNodes.TempHandle(base_type)
target = target_handle.ref(pos)
cmp_node = ExprNodes.PrimaryCmpNode(
pos, operator=u'==', operand1=node.operand1, operand2=target)
if_body = Nodes.StatListNode(
pos,
stats = [Nodes.SingleAssignmentNode(pos, lhs=result_ref, rhs=ExprNodes.BoolNode(pos, value=1)),
Nodes.BreakStatNode(pos)])
if_node = Nodes.IfStatNode(
pos,
if_clauses=[Nodes.IfClauseNode(pos, condition=cmp_node, body=if_body)],
else_clause=None)
for_loop = UtilNodes.TempsBlockNode(
pos,
temps = [target_handle],
body = Nodes.ForInStatNode(
pos,
target=target,
iterator=ExprNodes.IteratorNode(node.operand2.pos, sequence=node.operand2),
body=if_node,
else_clause=Nodes.SingleAssignmentNode(pos, lhs=result_ref, rhs=ExprNodes.BoolNode(pos, value=0))))
for_loop.analyse_expressions(self.current_scope)
for_loop = self(for_loop)
new_node = UtilNodes.TempResultFromStatNode(result_ref, for_loop)
if node.operator == 'not_in':
new_node = ExprNodes.NotNode(pos, operand=new_node)
return new_node
else:
self.visitchildren(node)
return node
def visit_ForInStatNode(self, node):
self.visitchildren(node)
return self._optimise_for_loop(node)
def _optimise_for_loop(self, node):
iterator = node.iterator.sequence
if iterator.type is Builtin.dict_type:
# like iterating over dict.keys()
return self._transform_dict_iteration(
node, dict_obj=iterator, keys=True, values=False)
# C array (slice) iteration?
if False:
plain_iterator = unwrap_coerced_node(iterator)
if isinstance(plain_iterator, ExprNodes.SliceIndexNode) and \
(plain_iterator.base.type.is_array or plain_iterator.base.type.is_ptr):
return self._transform_carray_iteration(node, plain_iterator)
if iterator.type.is_ptr or iterator.type.is_array:
return self._transform_carray_iteration(node, iterator)
if iterator.type in (Builtin.bytes_type, Builtin.unicode_type):
return self._transform_string_iteration(node, iterator)
# the rest is based on function calls
if not isinstance(iterator, ExprNodes.SimpleCallNode):
return node
function = iterator.function
# dict iteration?
if isinstance(function, ExprNodes.AttributeNode) and \
function.obj.type == Builtin.dict_type:
dict_obj = function.obj
method = function.attribute
keys = values = False
if method == 'iterkeys':
keys = True
elif method == 'itervalues':
values = True
elif method == 'iteritems':
keys = values = True
else:
return node
return self._transform_dict_iteration(
node, dict_obj, keys, values)
# enumerate() ?
if iterator.self is None and function.is_name and \
function.entry and function.entry.is_builtin and \
function.name == 'enumerate':
return self._transform_enumerate_iteration(node, iterator)
# range() iteration?
if Options.convert_range and node.target.type.is_int:
if iterator.self is None and function.is_name and \
function.entry and function.entry.is_builtin and \
function.name in ('range', 'xrange'):
return self._transform_range_iteration(node, iterator)
return node
PyUnicode_AS_UNICODE_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_py_unicode_ptr_type, [
PyrexTypes.CFuncTypeArg("s", Builtin.unicode_type, None)
])
PyUnicode_GET_SIZE_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_py_ssize_t_type, [
PyrexTypes.CFuncTypeArg("s", Builtin.unicode_type, None)
])
PyBytes_AS_STRING_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_char_ptr_type, [
PyrexTypes.CFuncTypeArg("s", Builtin.bytes_type, None)
])
PyBytes_GET_SIZE_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_py_ssize_t_type, [
PyrexTypes.CFuncTypeArg("s", Builtin.bytes_type, None)
])
def _transform_string_iteration(self, node, slice_node):
if not node.target.type.is_int:
return self._transform_carray_iteration(node, slice_node)
if slice_node.type is Builtin.unicode_type:
unpack_func = "PyUnicode_AS_UNICODE"
len_func = "PyUnicode_GET_SIZE"
unpack_func_type = self.PyUnicode_AS_UNICODE_func_type
len_func_type = self.PyUnicode_GET_SIZE_func_type
elif slice_node.type is Builtin.bytes_type:
unpack_func = "PyBytes_AS_STRING"
unpack_func_type = self.PyBytes_AS_STRING_func_type
len_func = "PyBytes_GET_SIZE"
len_func_type = self.PyBytes_GET_SIZE_func_type
else:
return node
unpack_temp_node = UtilNodes.LetRefNode(
slice_node.as_none_safe_node("'NoneType' is not iterable"))
slice_base_node = ExprNodes.PythonCapiCallNode(
slice_node.pos, unpack_func, unpack_func_type,
args = [unpack_temp_node],
is_temp = 0,
)
len_node = ExprNodes.PythonCapiCallNode(
slice_node.pos, len_func, len_func_type,
args = [unpack_temp_node],
is_temp = 0,
)
return UtilNodes.LetNode(
unpack_temp_node,
self._transform_carray_iteration(
node,
ExprNodes.SliceIndexNode(
slice_node.pos,
base = slice_base_node,
start = None,
step = None,
stop = len_node,
type = slice_base_node.type,
is_temp = 1,
)))
def _transform_carray_iteration(self, node, slice_node):
neg_step = False
if isinstance(slice_node, ExprNodes.SliceIndexNode):
slice_base = slice_node.base
start = slice_node.start
stop = slice_node.stop
step = None
if not stop:
if not slice_base.type.is_pyobject:
error(slice_node.pos, "C array iteration requires known end index")
return node
elif isinstance(slice_node, ExprNodes.IndexNode):
# slice_node.index must be a SliceNode
slice_base = slice_node.base
index = slice_node.index
start = index.start
stop = index.stop
step = index.step
if step:
if step.constant_result is None:
step = None
elif not isinstance(step.constant_result, (int,long)) \
or step.constant_result == 0 \
or step.constant_result > 0 and not stop \
or step.constant_result < 0 and not start:
if not slice_base.type.is_pyobject:
error(step.pos, "C array iteration requires known step size and end index")
return node
else:
# step sign is handled internally by ForFromStatNode
neg_step = step.constant_result < 0
step = ExprNodes.IntNode(step.pos, type=PyrexTypes.c_py_ssize_t_type,
value=abs(step.constant_result),
constant_result=abs(step.constant_result))
elif slice_node.type.is_array:
if slice_node.type.size is None:
error(step.pos, "C array iteration requires known end index")
return node
slice_base = slice_node
start = None
stop = ExprNodes.IntNode(
slice_node.pos, value=str(slice_node.type.size),
type=PyrexTypes.c_py_ssize_t_type, constant_result=slice_node.type.size)
step = None
else:
if not slice_node.type.is_pyobject:
error(slice_node.pos, "C array iteration requires known end index")
return node
if start:
if start.constant_result is None:
start = None
else:
start = start.coerce_to(PyrexTypes.c_py_ssize_t_type, self.current_scope)
if stop:
if stop.constant_result is None:
stop = None
else:
stop = stop.coerce_to(PyrexTypes.c_py_ssize_t_type, self.current_scope)
if stop is None:
if neg_step:
stop = ExprNodes.IntNode(
slice_node.pos, value='-1', type=PyrexTypes.c_py_ssize_t_type, constant_result=-1)
else:
error(slice_node.pos, "C array iteration requires known step size and end index")
return node
ptr_type = slice_base.type
if ptr_type.is_array:
ptr_type = ptr_type.element_ptr_type()
carray_ptr = slice_base.coerce_to_simple(self.current_scope)
if start and start.constant_result != 0:
start_ptr_node = ExprNodes.AddNode(
start.pos,
operand1=carray_ptr,
operator='+',
operand2=start,
type=ptr_type)
else:
start_ptr_node = carray_ptr
stop_ptr_node = ExprNodes.AddNode(
stop.pos,
operand1=ExprNodes.CloneNode(carray_ptr),
operator='+',
operand2=stop,
type=ptr_type
).coerce_to_simple(self.current_scope)
counter = UtilNodes.TempHandle(ptr_type)
counter_temp = counter.ref(node.target.pos)
if slice_base.type.is_string and node.target.type.is_pyobject:
# special case: char* -> bytes
target_value = ExprNodes.SliceIndexNode(
node.target.pos,
start=ExprNodes.IntNode(node.target.pos, value='0',
constant_result=0,
type=PyrexTypes.c_int_type),
stop=ExprNodes.IntNode(node.target.pos, value='1',
constant_result=1,
type=PyrexTypes.c_int_type),
base=counter_temp,
type=Builtin.bytes_type,
is_temp=1)
else:
target_value = ExprNodes.IndexNode(
node.target.pos,
index=ExprNodes.IntNode(node.target.pos, value='0',
constant_result=0,
type=PyrexTypes.c_int_type),
base=counter_temp,
is_buffer_access=False,
type=ptr_type.base_type)
if target_value.type != node.target.type:
target_value = target_value.coerce_to(node.target.type,
self.current_scope)
target_assign = Nodes.SingleAssignmentNode(
pos = node.target.pos,
lhs = node.target,
rhs = target_value)
body = Nodes.StatListNode(
node.pos,
stats = [target_assign, node.body])
for_node = Nodes.ForFromStatNode(
node.pos,
bound1=start_ptr_node, relation1=neg_step and '>=' or '<=',
target=counter_temp,
relation2=neg_step and '>' or '<', bound2=stop_ptr_node,
step=step, body=body,
else_clause=node.else_clause,
from_range=True)
return UtilNodes.TempsBlockNode(
node.pos, temps=[counter],
body=for_node)
def _transform_enumerate_iteration(self, node, enumerate_function):
args = enumerate_function.arg_tuple.args
if len(args) == 0:
error(enumerate_function.pos,
"enumerate() requires an iterable argument")
return node
elif len(args) > 1:
error(enumerate_function.pos,
"enumerate() takes at most 1 argument")
return node
if not node.target.is_sequence_constructor:
# leave this untouched for now
return node
targets = node.target.args
if len(targets) != 2:
# leave this untouched for now
return node
if not isinstance(targets[0], ExprNodes.NameNode):
# leave this untouched for now
return node
enumerate_target, iterable_target = targets
counter_type = enumerate_target.type
if not counter_type.is_pyobject and not counter_type.is_int:
# nothing we can do here, I guess
return node
temp = UtilNodes.LetRefNode(ExprNodes.IntNode(enumerate_function.pos,
value='0',
type=counter_type,
constant_result=0))
inc_expression = ExprNodes.AddNode(
enumerate_function.pos,
operand1 = temp,
operand2 = ExprNodes.IntNode(node.pos, value='1',
type=counter_type,
constant_result=1),
operator = '+',
type = counter_type,
is_temp = counter_type.is_pyobject
)
loop_body = [
Nodes.SingleAssignmentNode(
pos = enumerate_target.pos,
lhs = enumerate_target,
rhs = temp),
Nodes.SingleAssignmentNode(
pos = enumerate_target.pos,
lhs = temp,
rhs = inc_expression)
]
if isinstance(node.body, Nodes.StatListNode):
node.body.stats = loop_body + node.body.stats
else:
loop_body.append(node.body)
node.body = Nodes.StatListNode(
node.body.pos,
stats = loop_body)
node.target = iterable_target
node.item = node.item.coerce_to(iterable_target.type, self.current_scope)
node.iterator.sequence = enumerate_function.arg_tuple.args[0]
# recurse into loop to check for further optimisations
return UtilNodes.LetNode(temp, self._optimise_for_loop(node))
def _transform_range_iteration(self, node, range_function):
args = range_function.arg_tuple.args
if len(args) < 3:
step_pos = range_function.pos
step_value = 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, (int, long)):
# cannot determine step direction
return node
step_value = step.constant_result
if step_value == 0:
# will lead to an error elsewhere
return node
if not isinstance(step, ExprNodes.IntNode):
step = ExprNodes.IntNode(step_pos, value=str(step_value),
constant_result=step_value)
if step_value < 0:
step.value = str(-step_value)
relation1 = '>='
relation2 = '>'
else:
relation1 = '<='
relation2 = '<'
if len(args) == 1:
bound1 = ExprNodes.IntNode(range_function.pos, value='0',
constant_result=0)
bound2 = args[0].coerce_to_integer(self.current_scope)
else:
bound1 = args[0].coerce_to_integer(self.current_scope)
bound2 = args[1].coerce_to_integer(self.current_scope)
step = step.coerce_to_integer(self.current_scope)
if not bound2.is_literal:
# stop bound must be immutable => keep it in a temp var
bound2_is_temp = True
bound2 = UtilNodes.LetRefNode(bound2)
else:
bound2_is_temp = False
for_node = Nodes.ForFromStatNode(
node.pos,
target=node.target,
bound1=bound1, relation1=relation1,
relation2=relation2, bound2=bound2,
step=step, body=node.body,
else_clause=node.else_clause,
from_range=True)
if bound2_is_temp:
for_node = UtilNodes.LetNode(bound2, for_node)
return for_node
def _transform_dict_iteration(self, node, dict_obj, keys, values):
py_object_ptr = PyrexTypes.c_void_ptr_type
temps = []
temp = UtilNodes.TempHandle(PyrexTypes.py_object_type)
temps.append(temp)
dict_temp = temp.ref(dict_obj.pos)
temp = UtilNodes.TempHandle(PyrexTypes.c_py_ssize_t_type)
temps.append(temp)
pos_temp = temp.ref(node.pos)
pos_temp_addr = ExprNodes.AmpersandNode(
node.pos, operand=pos_temp,
type=PyrexTypes.c_ptr_type(PyrexTypes.c_py_ssize_t_type))
if keys:
temp = UtilNodes.TempHandle(py_object_ptr)
temps.append(temp)
key_temp = temp.ref(node.target.pos)
key_temp_addr = ExprNodes.AmpersandNode(
node.target.pos, operand=key_temp,
type=PyrexTypes.c_ptr_type(py_object_ptr))
else:
key_temp_addr = key_temp = ExprNodes.NullNode(
pos=node.target.pos)
if values:
temp = UtilNodes.TempHandle(py_object_ptr)
temps.append(temp)
value_temp = temp.ref(node.target.pos)
value_temp_addr = ExprNodes.AmpersandNode(
node.target.pos, operand=value_temp,
type=PyrexTypes.c_ptr_type(py_object_ptr))
else:
value_temp_addr = value_temp = ExprNodes.NullNode(
pos=node.target.pos)
key_target = value_target = node.target
tuple_target = None
if keys and values:
if node.target.is_sequence_constructor:
if len(node.target.args) == 2:
key_target, value_target = node.target.args
else:
# unusual case that may or may not lead to an error
return node
else:
tuple_target = node.target
def coerce_object_to(obj_node, dest_type):
if dest_type.is_pyobject:
if dest_type != obj_node.type:
if dest_type.is_extension_type or dest_type.is_builtin_type:
obj_node = ExprNodes.PyTypeTestNode(
obj_node, dest_type, self.current_scope, notnone=True)
result = ExprNodes.TypecastNode(
obj_node.pos,
operand = obj_node,
type = dest_type)
return (result, None)
else:
temp = UtilNodes.TempHandle(dest_type)
temps.append(temp)
temp_result = temp.ref(obj_node.pos)
class CoercedTempNode(ExprNodes.CoerceFromPyTypeNode):
def result(self):
return temp_result.result()
def generate_execution_code(self, code):
self.generate_result_code(code)
return (temp_result, CoercedTempNode(dest_type, obj_node, self.current_scope))
if isinstance(node.body, Nodes.StatListNode):
body = node.body
else:
body = Nodes.StatListNode(pos = node.body.pos,
stats = [node.body])
if tuple_target:
tuple_result = ExprNodes.TupleNode(
pos = tuple_target.pos,
args = [key_temp, value_temp],
is_temp = 1,
type = Builtin.tuple_type,
)
body.stats.insert(
0, Nodes.SingleAssignmentNode(
pos = tuple_target.pos,
lhs = tuple_target,
rhs = tuple_result))
else:
# execute all coercions before the assignments
coercion_stats = []
assign_stats = []
if keys:
temp_result, coercion = coerce_object_to(
key_temp, key_target.type)
if coercion:
coercion_stats.append(coercion)
assign_stats.append(
Nodes.SingleAssignmentNode(
pos = key_temp.pos,
lhs = key_target,
rhs = temp_result))
if values:
temp_result, coercion = coerce_object_to(
value_temp, value_target.type)
if coercion:
coercion_stats.append(coercion)
assign_stats.append(
Nodes.SingleAssignmentNode(
pos = value_temp.pos,
lhs = value_target,
rhs = temp_result))
body.stats[0:0] = coercion_stats + assign_stats
result_code = [
Nodes.SingleAssignmentNode(
pos = dict_obj.pos,
lhs = dict_temp,
rhs = dict_obj),
Nodes.SingleAssignmentNode(
pos = node.pos,
lhs = pos_temp,
rhs = ExprNodes.IntNode(node.pos, value='0',
constant_result=0)),
Nodes.WhileStatNode(
pos = node.pos,
condition = ExprNodes.SimpleCallNode(
pos = dict_obj.pos,
type = PyrexTypes.c_bint_type,
function = ExprNodes.NameNode(
pos = dict_obj.pos,
name = self.PyDict_Next_name,
type = self.PyDict_Next_func_type,
entry = self.PyDict_Next_entry),
args = [dict_temp, pos_temp_addr,
key_temp_addr, value_temp_addr]
),
body = body,
else_clause = node.else_clause
)
]
return UtilNodes.TempsBlockNode(
node.pos, temps=temps,
body=Nodes.StatListNode(
node.pos,
stats = result_code
))
class SwitchTransform(Visitor.VisitorTransform):
"""
This transformation tries to turn long if statements into C switch statements.
The requirement is that every clause be an (or of) var == value, where the var
is common among all clauses and both var and value are ints.
"""
NO_MATCH = (None, None, None)
def extract_conditions(self, cond, allow_not_in):
while True:
if isinstance(cond, ExprNodes.CoerceToTempNode):
cond = cond.arg
elif isinstance(cond, UtilNodes.EvalWithTempExprNode):
# this is what we get from the FlattenInListTransform
cond = cond.subexpression
elif isinstance(cond, ExprNodes.TypecastNode):
cond = cond.operand
else:
break
if isinstance(cond, ExprNodes.PrimaryCmpNode):
if cond.cascade is None and not cond.is_python_comparison():
if cond.operator == '==':
not_in = False
elif allow_not_in and cond.operator == '!=':
not_in = True
elif cond.is_c_string_contains() and \
isinstance(cond.operand2, (ExprNodes.UnicodeNode, ExprNodes.BytesNode)):
not_in = cond.operator == 'not_in'
if not_in and not allow_not_in:
return self.NO_MATCH
if isinstance(cond.operand2, ExprNodes.UnicodeNode) and \
cond.operand2.contains_surrogates():
# dealing with surrogates leads to different
# behaviour on wide and narrow Unicode
# platforms => refuse to optimise this case
return self.NO_MATCH
# this looks somewhat silly, but it does the right
# checks for NameNode and AttributeNode
if is_common_value(cond.operand1, cond.operand1):
return not_in, cond.operand1, self.extract_in_string_conditions(cond.operand2)
else:
return self.NO_MATCH
else:
return self.NO_MATCH
# this looks somewhat silly, but it does the right
# checks for NameNode and AttributeNode
if is_common_value(cond.operand1, cond.operand1):
if cond.operand2.is_literal:
return not_in, cond.operand1, [cond.operand2]
elif getattr(cond.operand2, 'entry', None) \
and cond.operand2.entry.is_const:
return not_in, cond.operand1, [cond.operand2]
if is_common_value(cond.operand2, cond.operand2):
if cond.operand1.is_literal:
return not_in, cond.operand2, [cond.operand1]
elif getattr(cond.operand1, 'entry', None) \
and cond.operand1.entry.is_const:
return not_in, cond.operand2, [cond.operand1]
elif isinstance(cond, ExprNodes.BoolBinopNode):
if cond.operator == 'or' or (allow_not_in and cond.operator == 'and'):
allow_not_in = (cond.operator == 'and')
not_in_1, t1, c1 = self.extract_conditions(cond.operand1, allow_not_in)
not_in_2, t2, c2 = self.extract_conditions(cond.operand2, allow_not_in)
if t1 is not None and not_in_1 == not_in_2 and is_common_value(t1, t2):
if (not not_in_1) or allow_not_in:
return not_in_1, t1, c1+c2
return self.NO_MATCH
def extract_in_string_conditions(self, string_literal):
if isinstance(string_literal, ExprNodes.UnicodeNode):
charvals = map(ord, set(string_literal.value))
charvals.sort()
return [ ExprNodes.IntNode(string_literal.pos, value=str(charval),
constant_result=charval)
for charval in charvals ]
else:
# this is a bit tricky as Py3's bytes type returns
# integers on iteration, whereas Py2 returns 1-char byte
# strings
characters = string_literal.value
characters = list(set([ characters[i:i+1] for i in range(len(characters)) ]))
characters.sort()
return [ ExprNodes.CharNode(string_literal.pos, value=charval,
constant_result=charval)
for charval in characters ]
def extract_common_conditions(self, common_var, condition, allow_not_in):
not_in, var, conditions = self.extract_conditions(condition, allow_not_in)
if var is None:
return self.NO_MATCH
elif common_var is not None and not is_common_value(var, common_var):
return self.NO_MATCH
elif not var.type.is_int or sum([not cond.type.is_int for cond in conditions]):
return self.NO_MATCH
return not_in, var, conditions
def has_duplicate_values(self, condition_values):
# duplicated values don't work in a switch statement
seen = set()
for value in condition_values:
if value.constant_result is not ExprNodes.not_a_constant:
if value.constant_result in seen:
return True
seen.add(value.constant_result)
else:
# this isn't completely safe as we don't know the
# final C value, but this is about the best we can do
seen.add(getattr(getattr(value, 'entry', None), 'cname'))
return False
def visit_IfStatNode(self, node):
common_var = None
cases = []
for if_clause in node.if_clauses:
_, common_var, conditions = self.extract_common_conditions(
common_var, if_clause.condition, False)
if common_var is None:
self.visitchildren(node)
return node
cases.append(Nodes.SwitchCaseNode(pos = if_clause.pos,
conditions = conditions,
body = if_clause.body))
if sum([ len(case.conditions) for case in cases ]) < 2:
self.visitchildren(node)
return node
if self.has_duplicate_values(sum([case.conditions for case in cases], [])):
self.visitchildren(node)
return node
common_var = unwrap_node(common_var)
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):
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):
self.visitchildren(node)
return node
return self.build_simple_switch_statement(
node, common_var, conditions, not_in,
node.true_val, node.false_val)
def visit_BoolBinopNode(self, node):
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):
self.visitchildren(node)
return node
return self.build_simple_switch_statement(
node, common_var, conditions, not_in,
ExprNodes.BoolNode(node.pos, value=True, constant_result=True),
ExprNodes.BoolNode(node.pos, value=False, constant_result=False))
def visit_PrimaryCmpNode(self, node):
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):
self.visitchildren(node)
return node
return self.build_simple_switch_statement(
node, common_var, conditions, not_in,
ExprNodes.BoolNode(node.pos, value=True, constant_result=True),
ExprNodes.BoolNode(node.pos, value=False, constant_result=False))
def build_simple_switch_statement(self, node, common_var, conditions,
not_in, true_val, false_val):
result_ref = UtilNodes.ResultRefNode(node)
true_body = Nodes.SingleAssignmentNode(
node.pos,
lhs = result_ref,
rhs = true_val,
first = True)
false_body = Nodes.SingleAssignmentNode(
node.pos,
lhs = result_ref,
rhs = false_val,
first = True)
if not_in:
true_body, false_body = false_body, true_body
cases = [Nodes.SwitchCaseNode(pos = node.pos,
conditions = conditions,
body = true_body)]
common_var = unwrap_node(common_var)
switch_node = Nodes.SwitchStatNode(pos = node.pos,
test = common_var,
cases = cases,
else_clause = false_body)
return UtilNodes.TempResultFromStatNode(result_ref, switch_node)
visit_Node = Visitor.VisitorTransform.recurse_to_children
class FlattenInListTransform(Visitor.VisitorTransform, SkipDeclarations):
"""
This transformation flattens "x in [val1, ..., valn]" into a sequential list
of comparisons.
"""
def visit_PrimaryCmpNode(self, node):
self.visitchildren(node)
if node.cascade is not None:
return node
elif node.operator == 'in':
conjunction = 'or'
eq_or_neq = '=='
elif node.operator == 'not_in':
conjunction = 'and'
eq_or_neq = '!='
else:
return node
if not isinstance(node.operand2, (ExprNodes.TupleNode,
ExprNodes.ListNode,
ExprNodes.SetNode)):
return node
args = node.operand2.args
if len(args) == 0:
return ExprNodes.BoolNode(pos = node.pos, value = node.operator == 'not_in')
lhs = UtilNodes.ResultRefNode(node.operand1)
conds = []
temps = []
for arg in args:
if not arg.is_simple():
# must evaluate all non-simple RHS before doing the comparisons
arg = UtilNodes.LetRefNode(arg)
temps.append(arg)
cond = ExprNodes.PrimaryCmpNode(
pos = node.pos,
operand1 = lhs,
operator = eq_or_neq,
operand2 = arg,
cascade = None)
conds.append(ExprNodes.TypecastNode(
pos = node.pos,
operand = cond,
type = PyrexTypes.c_bint_type))
def concat(left, right):
return ExprNodes.BoolBinopNode(
pos = node.pos,
operator = conjunction,
operand1 = left,
operand2 = right)
condition = reduce(concat, conds)
new_node = UtilNodes.EvalWithTempExprNode(lhs, condition)
for temp in temps[::-1]:
new_node = UtilNodes.EvalWithTempExprNode(temp, new_node)
return new_node
visit_Node = Visitor.VisitorTransform.recurse_to_children
class DropRefcountingTransform(Visitor.VisitorTransform):
"""Drop ref-counting in safe places.
"""
visit_Node = Visitor.VisitorTransform.recurse_to_children
def visit_ParallelAssignmentNode(self, node):
"""
Parallel swap assignments like 'a,b = b,a' are safe.
"""
left_names, right_names = [], []
left_indices, right_indices = [], []
temps = []
for stat in node.stats:
if isinstance(stat, Nodes.SingleAssignmentNode):
if not self._extract_operand(stat.lhs, left_names,
left_indices, temps):
return node
if not self._extract_operand(stat.rhs, right_names,
right_indices, temps):
return node
elif isinstance(stat, Nodes.CascadedAssignmentNode):
# FIXME
return node
else:
return node
if left_names or right_names:
# lhs/rhs names must be a non-redundant permutation
lnames = [ path for path, n in left_names ]
rnames = [ path for path, n in right_names ]
if set(lnames) != set(rnames):
return node
if len(set(lnames)) != len(right_names):
return node
if left_indices or right_indices:
# base name and index of index nodes must be a
# non-redundant permutation
lindices = []
for lhs_node in left_indices:
index_id = self._extract_index_id(lhs_node)
if not index_id:
return node
lindices.append(index_id)
rindices = []
for rhs_node in right_indices:
index_id = self._extract_index_id(rhs_node)
if not index_id:
return node
rindices.append(index_id)
if set(lindices) != set(rindices):
return node
if len(set(lindices)) != len(right_indices):
return node
# really supporting IndexNode requires support in
# __Pyx_GetItemInt(), so let's stop short for now
return node
temp_args = [t.arg for t in temps]
for temp in temps:
temp.use_managed_ref = False
for _, name_node in left_names + right_names:
if name_node not in temp_args:
name_node.use_managed_ref = False
for index_node in left_indices + right_indices:
index_node.use_managed_ref = False
return node
def _extract_operand(self, node, names, indices, temps):
node = unwrap_node(node)
if not node.type.is_pyobject:
return False
if isinstance(node, ExprNodes.CoerceToTempNode):
temps.append(node)
node = node.arg
name_path = []
obj_node = node
while isinstance(obj_node, ExprNodes.AttributeNode):
if obj_node.is_py_attr:
return False
name_path.append(obj_node.member)
obj_node = obj_node.obj
if isinstance(obj_node, ExprNodes.NameNode):
name_path.append(obj_node.name)
names.append( ('.'.join(name_path[::-1]), node) )
elif isinstance(node, ExprNodes.IndexNode):
if node.base.type != Builtin.list_type:
return False
if not node.index.type.is_int:
return False
if not isinstance(node.base, ExprNodes.NameNode):
return False
indices.append(node)
else:
return False
return True
def _extract_index_id(self, index_node):
base = index_node.base
index = index_node.index
if isinstance(index, ExprNodes.NameNode):
index_val = index.name
elif isinstance(index, ExprNodes.ConstNode):
# FIXME:
return None
else:
return None
return (base.name, index_val)
class EarlyReplaceBuiltinCalls(Visitor.EnvTransform):
"""Optimize some common calls to builtin types *before* the type
analysis phase and *after* the declarations analysis phase.
This transform cannot make use of any argument types, but it can
restructure the tree in a way that the type analysis phase can
respond to.
Introducing C function calls here may not be a good idea. Move
them to the OptimizeBuiltinCalls transform instead, which runs
after type analyis.
"""
# only intercept on call nodes
visit_Node = Visitor.VisitorTransform.recurse_to_children
def visit_SimpleCallNode(self, node):
self.visitchildren(node)
function = node.function
if not self._function_is_builtin_name(function):
return node
return self._dispatch_to_handler(node, function, node.args)
def visit_GeneralCallNode(self, node):
self.visitchildren(node)
function = node.function
if not self._function_is_builtin_name(function):
return node
arg_tuple = node.positional_args
if not isinstance(arg_tuple, ExprNodes.TupleNode):
return node
args = arg_tuple.args
return self._dispatch_to_handler(
node, function, args, node.keyword_args)
def _function_is_builtin_name(self, function):
if not function.is_name:
return False
entry = self.current_env().lookup(function.name)
if entry and getattr(entry, 'scope', None) is not Builtin.builtin_scope:
return False
# if entry is None, it's at least an undeclared name, so likely builtin
return True
def _dispatch_to_handler(self, node, function, args, kwargs=None):
if kwargs is None:
handler_name = '_handle_simple_function_%s' % function.name
else:
handler_name = '_handle_general_function_%s' % function.name
handle_call = getattr(self, handler_name, None)
if handle_call is not None:
if kwargs is None:
return handle_call(node, args)
else:
return handle_call(node, args, kwargs)
return node
def _inject_capi_function(self, node, cname, func_type, utility_code=None):
node.function = ExprNodes.PythonCapiFunctionNode(
node.function.pos, node.function.name, cname, func_type,
utility_code = utility_code)
def _error_wrong_arg_count(self, function_name, node, args, expected=None):
if not expected: # None or 0
arg_str = ''
elif isinstance(expected, basestring) or expected > 1:
arg_str = '...'
elif expected == 1:
arg_str = 'x'
else:
arg_str = ''
if expected is not None:
expected_str = 'expected %s, ' % expected
else:
expected_str = ''
error(node.pos, "%s(%s) called with wrong number of args, %sfound %d" % (
function_name, arg_str, expected_str, len(args)))
# specific handlers for simple call nodes
def _handle_simple_function_float(self, node, pos_args):
if len(pos_args) == 0:
return ExprNodes.FloatNode(node.pos, value='0.0')
if len(pos_args) > 1:
self._error_wrong_arg_count('float', node, pos_args, 1)
return node
class YieldNodeCollector(Visitor.TreeVisitor):
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
def __visit_GeneratorExpressionNode(self, node):
# enable when we support generic generator expressions
#
# everything below this node is out of scope
pass
def _find_single_yield_expression(self, node):
collector = self.YieldNodeCollector()
collector.visitchildren(node)
if len(collector.yield_nodes) != 1:
return None, None
yield_node = collector.yield_nodes[0]
try:
return (yield_node.arg, collector.yield_stat_nodes[yield_node])
except KeyError:
return None, None
def _handle_simple_function_all(self, node, pos_args):
"""Transform
_result = all(x for L in LL for x in L)
into
for L in LL:
for x in L:
if not x:
_result = False
break
else:
continue
break
else:
_result = True
"""
return self._transform_any_all(node, pos_args, False)
def _handle_simple_function_any(self, node, pos_args):
"""Transform
_result = any(x for L in LL for x in L)
into
for L in LL:
for x in L:
if x:
_result = True
break
else:
continue
break
else:
_result = False
"""
return self._transform_any_all(node, pos_args, True)
def _transform_any_all(self, node, pos_args, is_any):
if len(pos_args) != 1:
return node
if not isinstance(pos_args[0], ExprNodes.GeneratorExpressionNode):
return node
gen_expr_node = pos_args[0]
loop_node = gen_expr_node.loop
yield_expression, yield_stat_node = self._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)
result_ref = UtilNodes.ResultRefNode(pos=node.pos, type=PyrexTypes.c_bint_type)
test_node = Nodes.IfStatNode(
yield_expression.pos,
else_clause = None,
if_clauses = [ Nodes.IfClauseNode(
yield_expression.pos,
condition = condition,
body = Nodes.StatListNode(
node.pos,
stats = [
Nodes.SingleAssignmentNode(
node.pos,
lhs = result_ref,
rhs = ExprNodes.BoolNode(yield_expression.pos, value = is_any,
constant_result = is_any)),
Nodes.BreakStatNode(node.pos)
])) ]
)
loop = loop_node
while isinstance(loop.body, Nodes.LoopNode):
next_loop = loop.body
loop.body = Nodes.StatListNode(loop.body.pos, stats = [
loop.body,
Nodes.BreakStatNode(yield_expression.pos)
])
next_loop.else_clause = Nodes.ContinueStatNode(yield_expression.pos)
loop = next_loop
loop_node.else_clause = Nodes.SingleAssignmentNode(
node.pos,
lhs = result_ref,
rhs = ExprNodes.BoolNode(yield_expression.pos, value = not is_any,
constant_result = not is_any))
Visitor.recursively_replace_node(loop_node, yield_stat_node, test_node)
return ExprNodes.InlinedGeneratorExpressionNode(
gen_expr_node.pos, loop = loop_node, result_node = result_ref,
expr_scope = gen_expr_node.expr_scope, orig_func = is_any and 'any' or 'all')
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):
return node
if not isinstance(pos_args[0], ExprNodes.GeneratorExpressionNode):
return node
gen_expr_node = pos_args[0]
loop_node = gen_expr_node.loop
yield_expression, yield_stat_node = self._find_single_yield_expression(loop_node)
if yield_expression is None:
return node
if len(pos_args) == 1:
start = ExprNodes.IntNode(node.pos, value='0', constant_result=0)
else:
start = pos_args[1]
result_ref = UtilNodes.ResultRefNode(pos=node.pos, type=PyrexTypes.py_object_type)
add_node = Nodes.SingleAssignmentNode(
yield_expression.pos,
lhs = result_ref,
rhs = ExprNodes.binop_node(node.pos, '+', result_ref, yield_expression)
)
Visitor.recursively_replace_node(loop_node, yield_stat_node, add_node)
exec_code = Nodes.StatListNode(
node.pos,
stats = [
Nodes.SingleAssignmentNode(
start.pos,
lhs = UtilNodes.ResultRefNode(pos=node.pos, expression=result_ref),
rhs = start,
first = True),
loop_node
])
return ExprNodes.InlinedGeneratorExpressionNode(
gen_expr_node.pos, loop = exec_code, result_node = result_ref,
expr_scope = gen_expr_node.expr_scope, orig_func = 'sum')
def _handle_simple_function_min(self, node, pos_args):
return self._optimise_min_max(node, pos_args, '<')
def _handle_simple_function_max(self, node, pos_args):
return self._optimise_min_max(node, pos_args, '>')
def _optimise_min_max(self, node, args, operator):
"""Replace min(a,b,...) and max(a,b,...) by explicit comparison code.
"""
if len(args) <= 1:
# leave this to Python
return node
cascaded_nodes = map(UtilNodes.ResultRefNode, args[1:])
last_result = args[0]
for arg_node in cascaded_nodes:
result_ref = UtilNodes.ResultRefNode(last_result)
last_result = ExprNodes.CondExprNode(
arg_node.pos,
true_val = arg_node,
false_val = result_ref,
test = ExprNodes.PrimaryCmpNode(
arg_node.pos,
operand1 = arg_node,
operator = operator,
operand2 = result_ref,
)
)
last_result = UtilNodes.EvalWithTempExprNode(result_ref, last_result)
for ref_node in cascaded_nodes[::-1]:
last_result = UtilNodes.EvalWithTempExprNode(ref_node, last_result)
return last_result
def _DISABLED_handle_simple_function_tuple(self, node, pos_args):
if len(pos_args) == 0:
return ExprNodes.TupleNode(node.pos, args=[], constant_result=())
# This is a bit special - for iterables (including genexps),
# Python actually overallocates and resizes a newly created
# tuple incrementally while reading items, which we can't
# easily do without explicit node support. Instead, we read
# the items into a list and then copy them into a tuple of the
# final size. This takes up to twice as much memory, but will
# have to do until we have real support for genexps.
result = self._transform_list_set_genexpr(node, pos_args, ExprNodes.ListNode)
if result is not node:
return ExprNodes.AsTupleNode(node.pos, arg=result)
return node
def _handle_simple_function_list(self, node, pos_args):
if len(pos_args) == 0:
return ExprNodes.ListNode(node.pos, args=[], constant_result=[])
return self._transform_list_set_genexpr(node, pos_args, ExprNodes.ListNode)
def _handle_simple_function_set(self, node, pos_args):
if len(pos_args) == 0:
return ExprNodes.SetNode(node.pos, args=[], constant_result=set())
return self._transform_list_set_genexpr(node, pos_args, ExprNodes.SetNode)
def _transform_list_set_genexpr(self, node, pos_args, container_node_class):
"""Replace set(genexpr) and list(genexpr) by a literal comprehension.
"""
if len(pos_args) > 1:
return node
if not isinstance(pos_args[0], ExprNodes.GeneratorExpressionNode):
return node
gen_expr_node = pos_args[0]
loop_node = gen_expr_node.loop
yield_expression, yield_stat_node = self._find_single_yield_expression(loop_node)
if yield_expression is None:
return node
target_node = container_node_class(node.pos, args=[])
append_node = ExprNodes.ComprehensionAppendNode(
yield_expression.pos,
expr = yield_expression,
target = ExprNodes.CloneNode(target_node))
Visitor.recursively_replace_node(loop_node, yield_stat_node, append_node)
setcomp = ExprNodes.ComprehensionNode(
node.pos,
has_local_scope = True,
expr_scope = gen_expr_node.expr_scope,
loop = loop_node,
append = append_node,
target = target_node)
append_node.target = setcomp
return setcomp
def _handle_simple_function_dict(self, node, pos_args):
"""Replace dict( (a,b) for ... ) by a literal { a:b for ... }.
"""
if len(pos_args) == 0:
return ExprNodes.DictNode(node.pos, key_value_pairs=[], constant_result={})
if len(pos_args) > 1:
return node
if not isinstance(pos_args[0], ExprNodes.GeneratorExpressionNode):
return node
gen_expr_node = pos_args[0]
loop_node = gen_expr_node.loop
yield_expression, yield_stat_node = self._find_single_yield_expression(loop_node)
if yield_expression is None:
return node
if not isinstance(yield_expression, ExprNodes.TupleNode):
return node
if len(yield_expression.args) != 2:
return node
target_node = ExprNodes.DictNode(node.pos, key_value_pairs=[])
append_node = ExprNodes.DictComprehensionAppendNode(
yield_expression.pos,
key_expr = yield_expression.args[0],
value_expr = yield_expression.args[1],
target = ExprNodes.CloneNode(target_node))
Visitor.recursively_replace_node(loop_node, yield_stat_node, append_node)
dictcomp = ExprNodes.ComprehensionNode(
node.pos,
has_local_scope = True,
expr_scope = gen_expr_node.expr_scope,
loop = loop_node,
append = append_node,
target = target_node)
append_node.target = dictcomp
return dictcomp
# specific handlers for general call nodes
def _handle_general_function_dict(self, node, pos_args, kwargs):
"""Replace dict(a=b,c=d,...) by the underlying keyword dict
construction which is done anyway.
"""
if len(pos_args) > 0:
return node
if not isinstance(kwargs, ExprNodes.DictNode):
return node
if node.starstar_arg:
# we could optimize this by updating the kw dict instead
return node
return kwargs
class OptimizeBuiltinCalls(Visitor.EnvTransform):
"""Optimize some common methods calls and instantiation patterns
for builtin types *after* the type analysis phase.
Running after type analysis, this transform can only perform
function replacements that do not alter the function return type
in a way that was not anticipated by the type analysis.
"""
# only intercept on call nodes
visit_Node = Visitor.VisitorTransform.recurse_to_children
def visit_GeneralCallNode(self, node):
self.visitchildren(node)
function = node.function
if not function.type.is_pyobject:
return node
arg_tuple = node.positional_args
if not isinstance(arg_tuple, ExprNodes.TupleNode):
return node
if node.starstar_arg:
return node
args = arg_tuple.args
return self._dispatch_to_handler(
node, function, args, node.keyword_args)
def visit_SimpleCallNode(self, node):
self.visitchildren(node)
function = node.function
if function.type.is_pyobject:
arg_tuple = node.arg_tuple
if not isinstance(arg_tuple, ExprNodes.TupleNode):
return node
args = arg_tuple.args
else:
args = node.args
return self._dispatch_to_handler(
node, function, args)
### cleanup to avoid redundant coercions to/from Python types
def _visit_PyTypeTestNode(self, node):
# disabled - appears to break assignments in some cases, and
# also drops a None check, which might still be required
"""Flatten redundant type checks after tree changes.
"""
old_arg = node.arg
self.visitchildren(node)
if old_arg is node.arg or node.arg.type != node.type:
return node
return node.arg
def visit_TypecastNode(self, node):
"""
Drop redundant type casts.
"""
self.visitchildren(node)
if node.type == node.operand.type:
return node.operand
return node
def visit_CoerceToBooleanNode(self, node):
"""Drop redundant conversion nodes after tree changes.
"""
self.visitchildren(node)
arg = node.arg
if isinstance(arg, ExprNodes.PyTypeTestNode):
arg = arg.arg
if isinstance(arg, ExprNodes.CoerceToPyTypeNode):
if arg.type in (PyrexTypes.py_object_type, Builtin.bool_type):
return arg.arg.coerce_to_boolean(self.current_env())
return node
def visit_CoerceFromPyTypeNode(self, node):
"""Drop redundant conversion nodes after tree changes.
Also, optimise away calls to Python's builtin int() and
float() if the result is going to be coerced back into a C
type anyway.
"""
self.visitchildren(node)
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:
return arg
else:
return arg.coerce_to(node.type, self.current_env())
if isinstance(arg, ExprNodes.PyTypeTestNode):
arg = arg.arg
if isinstance(arg, ExprNodes.CoerceToPyTypeNode):
if arg.type is PyrexTypes.py_object_type:
if node.type.assignable_from(arg.arg.type):
# completely redundant C->Py->C coercion
return arg.arg.coerce_to(node.type, self.current_env())
if isinstance(arg, ExprNodes.SimpleCallNode):
if node.type.is_int or node.type.is_float:
return self._optimise_numeric_cast_call(node, arg)
elif isinstance(arg, ExprNodes.IndexNode) and not arg.is_buffer_access:
index_node = arg.index
if isinstance(index_node, ExprNodes.CoerceToPyTypeNode):
index_node = index_node.arg
if index_node.type.is_int:
return self._optimise_int_indexing(node, arg, index_node)
return node
PyBytes_GetItemInt_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_char_type, [
PyrexTypes.CFuncTypeArg("bytes", Builtin.bytes_type, None),
PyrexTypes.CFuncTypeArg("index", PyrexTypes.c_py_ssize_t_type, None),
PyrexTypes.CFuncTypeArg("check_bounds", PyrexTypes.c_int_type, None),
],
exception_value = "((char)-1)",
exception_check = True)
def _optimise_int_indexing(self, coerce_node, arg, index_node):
env = self.current_env()
bound_check_bool = env.directives['boundscheck'] and 1 or 0
if arg.base.type is Builtin.bytes_type:
if coerce_node.type in (PyrexTypes.c_char_type, PyrexTypes.c_uchar_type):
# bytes[index] -> char
bound_check_node = ExprNodes.IntNode(
coerce_node.pos, value=str(bound_check_bool),
constant_result=bound_check_bool)
node = ExprNodes.PythonCapiCallNode(
coerce_node.pos, "__Pyx_PyBytes_GetItemInt",
self.PyBytes_GetItemInt_func_type,
args = [
arg.base.as_none_safe_node("'NoneType' object is not subscriptable"),
index_node.coerce_to(PyrexTypes.c_py_ssize_t_type, env),
bound_check_node,
],
is_temp = True,
utility_code=bytes_index_utility_code)
if coerce_node.type is not PyrexTypes.c_char_type:
node = node.coerce_to(coerce_node.type, env)
return node
return coerce_node
def _optimise_numeric_cast_call(self, node, arg):
function = arg.function
if not isinstance(function, ExprNodes.NameNode) \
or not function.type.is_builtin_type \
or not isinstance(arg.arg_tuple, ExprNodes.TupleNode):
return node
args = arg.arg_tuple.args
if 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 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 function.name == 'float':
if func_arg.type.is_float or node.type.is_float:
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)
return node
### dispatch to specific optimisers
def _find_handler(self, match_name, has_kwargs):
call_type = has_kwargs and 'general' or 'simple'
handler = getattr(self, '_handle_%s_%s' % (call_type, match_name), None)
if handler is None:
handler = getattr(self, '_handle_any_%s' % match_name, None)
return handler
def _dispatch_to_handler(self, node, function, arg_list, kwargs=None):
if function.is_name:
# we only consider functions that are either builtin
# Python functions or builtins that were already replaced
# into a C function call (defined in the builtin scope)
if not function.entry:
return node
is_builtin = function.entry.is_builtin \
or getattr(function.entry, 'scope', None) is Builtin.builtin_scope
if not is_builtin:
return node
function_handler = self._find_handler(
"function_%s" % function.name, kwargs)
if function_handler is None:
return node
if kwargs:
return function_handler(node, arg_list, kwargs)
else:
return function_handler(node, arg_list)
elif function.is_attribute and function.type.is_pyobject:
attr_name = function.attribute
self_arg = function.obj
obj_type = self_arg.type
is_unbound_method = False
if obj_type.is_builtin_type:
if obj_type is Builtin.type_type and arg_list and \
arg_list[0].type.is_pyobject:
# calling an unbound method like 'list.append(L,x)'
# (ignoring 'type.mro()' here ...)
type_name = function.obj.name
self_arg = None
is_unbound_method = True
else:
type_name = obj_type.name
else:
type_name = "object" # safety measure
method_handler = self._find_handler(
"method_%s_%s" % (type_name, attr_name), kwargs)
if method_handler is None:
if attr_name in TypeSlots.method_name_to_slot \
or attr_name == '__new__':
method_handler = self._find_handler(
"slot%s" % attr_name, kwargs)
if method_handler is None:
return node
if self_arg is not None:
arg_list = [self_arg] + list(arg_list)
if kwargs:
return method_handler(node, arg_list, kwargs, is_unbound_method)
else:
return method_handler(node, arg_list, is_unbound_method)
else:
return node
def _error_wrong_arg_count(self, function_name, node, args, expected=None):
if not expected: # None or 0
arg_str = ''
elif isinstance(expected, basestring) or expected > 1:
arg_str = '...'
elif expected == 1:
arg_str = 'x'
else:
arg_str = ''
if expected is not None:
expected_str = 'expected %s, ' % expected
else:
expected_str = ''
error(node.pos, "%s(%s) called with wrong number of args, %sfound %d" % (
function_name, arg_str, expected_str, len(args)))
### builtin types
PyDict_Copy_func_type = PyrexTypes.CFuncType(
Builtin.dict_type, [
PyrexTypes.CFuncTypeArg("dict", Builtin.dict_type, None)
])
def _handle_simple_function_dict(self, node, pos_args):
"""Replace dict(some_dict) by PyDict_Copy(some_dict).
"""
if len(pos_args) != 1:
return node
arg = pos_args[0]
if arg.type is Builtin.dict_type:
arg = arg.as_none_safe_node("'NoneType' is not iterable")
return ExprNodes.PythonCapiCallNode(
node.pos, "PyDict_Copy", self.PyDict_Copy_func_type,
args = [arg],
is_temp = node.is_temp
)
return node
PyList_AsTuple_func_type = PyrexTypes.CFuncType(
Builtin.tuple_type, [
PyrexTypes.CFuncTypeArg("list", Builtin.list_type, None)
])
def _handle_simple_function_tuple(self, node, pos_args):
"""Replace tuple([...]) by a call to PyList_AsTuple.
"""
if len(pos_args) != 1:
return node
list_arg = pos_args[0]
if list_arg.type is not Builtin.list_type:
return node
if not isinstance(list_arg, (ExprNodes.ComprehensionNode,
ExprNodes.ListNode)):
pos_args[0] = list_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
)
PyObject_AsDouble_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_double_type, [
PyrexTypes.CFuncTypeArg("obj", PyrexTypes.py_object_type, None),
],
exception_value = "((double)-1)",
exception_check = True)
def _handle_simple_function_float(self, node, pos_args):
"""Transform float() into either a C type cast or a faster C
function call.
"""
# Note: this requires the float() function to be typed as
# returning a C 'double'
if len(pos_args) == 0:
return ExprNode.FloatNode(
node, value="0.0", constant_result=0.0
).coerce_to(Builtin.float_type, self.current_env())
elif len(pos_args) != 1:
self._error_wrong_arg_count('float', node, pos_args, '0 or 1')
return node
func_arg = pos_args[0]
if isinstance(func_arg, ExprNodes.CoerceToPyTypeNode):
func_arg = func_arg.arg
if func_arg.type is PyrexTypes.c_double_type:
return func_arg
elif node.type.assignable_from(func_arg.type) or func_arg.type.is_numeric:
return ExprNodes.TypecastNode(
node.pos, operand=func_arg, type=node.type)
return ExprNodes.PythonCapiCallNode(
node.pos, "__Pyx_PyObject_AsDouble",
self.PyObject_AsDouble_func_type,
args = pos_args,
is_temp = node.is_temp,
utility_code = pyobject_as_double_utility_code,
py_name = "float")
def _handle_simple_function_bool(self, node, pos_args):
"""Transform bool(x) into a type coercion to a boolean.
"""
if len(pos_args) == 0:
return ExprNodes.BoolNode(
node.pos, value=False, constant_result=False
).coerce_to(Builtin.bool_type, self.current_env())
elif len(pos_args) != 1:
self._error_wrong_arg_count('bool', node, pos_args, '0 or 1')
return node
else:
return pos_args[0].coerce_to_boolean(
self.current_env()).coerce_to_pyobject(self.current_env())
### builtin functions
PyObject_GetAttr2_func_type = PyrexTypes.CFuncType(
PyrexTypes.py_object_type, [
PyrexTypes.CFuncTypeArg("object", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("attr_name", PyrexTypes.py_object_type, None),
])
PyObject_GetAttr3_func_type = PyrexTypes.CFuncType(
PyrexTypes.py_object_type, [
PyrexTypes.CFuncTypeArg("object", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("attr_name", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("default", PyrexTypes.py_object_type, None),
])
def _handle_simple_function_getattr(self, node, pos_args):
"""Replace 2/3 argument forms of getattr() by C-API calls.
"""
if len(pos_args) == 2:
return ExprNodes.PythonCapiCallNode(
node.pos, "PyObject_GetAttr", self.PyObject_GetAttr2_func_type,
args = pos_args,
may_return_none = True,
is_temp = node.is_temp)
elif len(pos_args) == 3:
return ExprNodes.PythonCapiCallNode(
node.pos, "__Pyx_GetAttr3", self.PyObject_GetAttr3_func_type,
args = pos_args,
may_return_none = True,
is_temp = node.is_temp,
utility_code = Builtin.getattr3_utility_code)
else:
self._error_wrong_arg_count('getattr', node, pos_args, '2 or 3')
return node
PyObject_GetIter_func_type = PyrexTypes.CFuncType(
PyrexTypes.py_object_type, [
PyrexTypes.CFuncTypeArg("object", PyrexTypes.py_object_type, None),
])
PyCallIter_New_func_type = PyrexTypes.CFuncType(
PyrexTypes.py_object_type, [
PyrexTypes.CFuncTypeArg("object", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("sentinel", PyrexTypes.py_object_type, None),
])
def _handle_simple_function_iter(self, node, pos_args):
"""Replace 1/2 argument forms of iter() by C-API calls.
"""
if len(pos_args) == 1:
return ExprNodes.PythonCapiCallNode(
node.pos, "PyObject_GetIter", self.PyObject_GetIter_func_type,
args = pos_args,
may_return_none = True,
is_temp = node.is_temp)
elif len(pos_args) == 2:
return ExprNodes.PythonCapiCallNode(
node.pos, "PyCallIter_New", self.PyCallIter_New_func_type,
args = pos_args,
is_temp = node.is_temp)
else:
self._error_wrong_arg_count('iter', node, pos_args, '1 or 2')
return node
Pyx_strlen_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_size_t_type, [
PyrexTypes.CFuncTypeArg("bytes", PyrexTypes.c_char_ptr_type, None)
])
PyObject_Size_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_py_ssize_t_type, [
PyrexTypes.CFuncTypeArg("obj", PyrexTypes.py_object_type, None)
])
_map_to_capi_len_function = {
Builtin.unicode_type : "PyUnicode_GET_SIZE",
Builtin.bytes_type : "PyBytes_GET_SIZE",
Builtin.list_type : "PyList_GET_SIZE",
Builtin.tuple_type : "PyTuple_GET_SIZE",
Builtin.dict_type : "PyDict_Size",
Builtin.set_type : "PySet_Size",
Builtin.frozenset_type : "PySet_Size",
}.get
def _handle_simple_function_len(self, node, pos_args):
"""Replace len(char*) by the equivalent call to strlen() and
len(known_builtin_type) by an equivalent C-API call.
"""
if len(pos_args) != 1:
self._error_wrong_arg_count('len', node, pos_args, 1)
return node
arg = pos_args[0]
if isinstance(arg, ExprNodes.CoerceToPyTypeNode):
arg = arg.arg
if arg.type.is_string:
new_node = ExprNodes.PythonCapiCallNode(
node.pos, "strlen", self.Pyx_strlen_func_type,
args = [arg],
is_temp = node.is_temp,
utility_code = include_string_h_utility_code)
elif arg.type.is_pyobject:
cfunc_name = self._map_to_capi_len_function(arg.type)
if cfunc_name is None:
return node
arg = arg.as_none_safe_node(
"object of type 'NoneType' has no len()")
new_node = ExprNodes.PythonCapiCallNode(
node.pos, cfunc_name, self.PyObject_Size_func_type,
args = [arg],
is_temp = node.is_temp)
elif arg.type is PyrexTypes.c_py_unicode_type:
return ExprNodes.IntNode(node.pos, value='1', constant_result=1,
type=node.type)
else:
return node
if node.type not in (PyrexTypes.c_size_t_type, PyrexTypes.c_py_ssize_t_type):
new_node = new_node.coerce_to(node.type, self.current_env())
return new_node
Pyx_Type_func_type = PyrexTypes.CFuncType(
Builtin.type_type, [
PyrexTypes.CFuncTypeArg("object", PyrexTypes.py_object_type, None)
])
def _handle_simple_function_type(self, node, pos_args):
"""Replace type(o) by a macro call to Py_TYPE(o).
"""
if len(pos_args) != 1:
return node
node = ExprNodes.PythonCapiCallNode(
node.pos, "Py_TYPE", self.Pyx_Type_func_type,
args = pos_args,
is_temp = False)
return ExprNodes.CastNode(node, PyrexTypes.py_object_type)
Py_type_check_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_bint_type, [
PyrexTypes.CFuncTypeArg("arg", PyrexTypes.py_object_type, None)
])
def _handle_simple_function_isinstance(self, node, pos_args):
"""Replace isinstance() checks against builtin types by the
corresponding C-API call.
"""
if len(pos_args) != 2:
return node
arg, types = pos_args
temp = None
if isinstance(types, ExprNodes.TupleNode):
types = types.args
arg = temp = UtilNodes.ResultRefNode(arg)
elif types.type is Builtin.type_type:
types = [types]
else:
return node
tests = []
test_nodes = []
env = self.current_env()
for test_type_node in types:
if not test_type_node.entry:
return node
entry = env.lookup(test_type_node.entry.name)
if not entry or not entry.type or not entry.type.is_builtin_type:
return node
type_check_function = entry.type.type_check_function(exact=False)
if not type_check_function:
return node
if type_check_function not in tests:
tests.append(type_check_function)
test_nodes.append(
ExprNodes.PythonCapiCallNode(
test_type_node.pos, type_check_function, self.Py_type_check_func_type,
args = [arg],
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)
or_node.type = PyrexTypes.c_bint_type
or_node.is_temp = True
return or_node
test_node = reduce(join_with_or, test_nodes).coerce_to(node.type, env)
if temp is not None:
test_node = UtilNodes.EvalWithTempExprNode(temp, test_node)
return test_node
def _handle_simple_function_ord(self, node, pos_args):
"""Unpack ord(Py_UNICODE).
"""
if len(pos_args) != 1:
return node
arg = pos_args[0]
if isinstance(arg, ExprNodes.CoerceToPyTypeNode):
if arg.arg.type is PyrexTypes.c_py_unicode_type:
return arg.arg.coerce_to(node.type, self.current_env())
return node
### special methods
Pyx_tp_new_func_type = PyrexTypes.CFuncType(
PyrexTypes.py_object_type, [
PyrexTypes.CFuncTypeArg("type", Builtin.type_type, None)
])
def _handle_simple_slot__new__(self, node, args, is_unbound_method):
"""Replace 'exttype.__new__(exttype)' by a call to exttype->tp_new()
"""
obj = node.function.obj
if not is_unbound_method or len(args) != 1:
return node
type_arg = args[0]
if not obj.is_name or not type_arg.is_name:
# play safe
return node
if obj.type != Builtin.type_type or type_arg.type != Builtin.type_type:
# not a known type, play safe
return node
if not type_arg.type_entry or not obj.type_entry:
if obj.name != type_arg.name:
return node
# otherwise, we know it's a type and we know it's the same
# type for both - that should do
elif type_arg.type_entry != obj.type_entry:
# different types - may or may not lead to an error at runtime
return node
# FIXME: we could potentially look up the actual tp_new C
# method of the extension type and call that instead of the
# generic slot. That would also allow us to pass parameters
# efficiently.
if not type_arg.type_entry:
# arbitrary variable, needs a None check for safety
type_arg = type_arg.as_none_safe_node(
"object.__new__(X): X is not a type object (NoneType)")
return ExprNodes.PythonCapiCallNode(
node.pos, "__Pyx_tp_new", self.Pyx_tp_new_func_type,
args = [type_arg],
utility_code = tpnew_utility_code,
is_temp = node.is_temp
)
### methods of builtin types
PyObject_Append_func_type = PyrexTypes.CFuncType(
PyrexTypes.py_object_type, [
PyrexTypes.CFuncTypeArg("list", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("item", PyrexTypes.py_object_type, None),
])
def _handle_simple_method_object_append(self, node, args, is_unbound_method):
"""Optimistic optimisation as X.append() is almost always
referring to a list.
"""
if len(args) != 2:
return node
return ExprNodes.PythonCapiCallNode(
node.pos, "__Pyx_PyObject_Append", self.PyObject_Append_func_type,
args = args,
may_return_none = True,
is_temp = node.is_temp,
utility_code = append_utility_code
)
PyObject_Pop_func_type = PyrexTypes.CFuncType(
PyrexTypes.py_object_type, [
PyrexTypes.CFuncTypeArg("list", PyrexTypes.py_object_type, None),
])
PyObject_PopIndex_func_type = PyrexTypes.CFuncType(
PyrexTypes.py_object_type, [
PyrexTypes.CFuncTypeArg("list", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("index", PyrexTypes.c_long_type, None),
])
def _handle_simple_method_object_pop(self, node, args, is_unbound_method):
"""Optimistic optimisation as X.pop([n]) is almost always
referring to a list.
"""
if len(args) == 1:
return ExprNodes.PythonCapiCallNode(
node.pos, "__Pyx_PyObject_Pop", self.PyObject_Pop_func_type,
args = args,
may_return_none = True,
is_temp = node.is_temp,
utility_code = pop_utility_code
)
elif len(args) == 2:
if isinstance(args[1], ExprNodes.CoerceToPyTypeNode) and args[1].arg.type.is_int:
original_type = args[1].arg.type
if PyrexTypes.widest_numeric_type(original_type, PyrexTypes.c_py_ssize_t_type) == PyrexTypes.c_py_ssize_t_type:
args[1] = args[1].arg
return ExprNodes.PythonCapiCallNode(
node.pos, "__Pyx_PyObject_PopIndex", self.PyObject_PopIndex_func_type,
args = args,
may_return_none = True,
is_temp = node.is_temp,
utility_code = pop_index_utility_code
)
return node
_handle_simple_method_list_pop = _handle_simple_method_object_pop
PyList_Append_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_int_type, [
PyrexTypes.CFuncTypeArg("list", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("item", PyrexTypes.py_object_type, None),
],
exception_value = "-1")
def _handle_simple_method_list_append(self, node, args, is_unbound_method):
"""Call PyList_Append() instead of l.append().
"""
if len(args) != 2:
self._error_wrong_arg_count('list.append', node, args, 2)
return node
return self._substitute_method_call(
node, "PyList_Append", self.PyList_Append_func_type,
'append', is_unbound_method, args)
single_param_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_int_type, [
PyrexTypes.CFuncTypeArg("obj", PyrexTypes.py_object_type, None),
],
exception_value = "-1")
def _handle_simple_method_list_sort(self, node, args, is_unbound_method):
"""Call PyList_Sort() instead of the 0-argument l.sort().
"""
if len(args) != 1:
return node
return self._substitute_method_call(
node, "PyList_Sort", self.single_param_func_type,
'sort', is_unbound_method, args)
def _handle_simple_method_list_reverse(self, node, args, is_unbound_method):
"""Call PyList_Reverse() instead of l.reverse().
"""
if len(args) != 1:
self._error_wrong_arg_count('list.reverse', node, args, 1)
return node
return self._substitute_method_call(
node, "PyList_Reverse", self.single_param_func_type,
'reverse', is_unbound_method, args)
Pyx_PyDict_GetItem_func_type = PyrexTypes.CFuncType(
PyrexTypes.py_object_type, [
PyrexTypes.CFuncTypeArg("dict", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("key", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("default", PyrexTypes.py_object_type, None),
])
def _handle_simple_method_dict_get(self, node, args, is_unbound_method):
"""Replace dict.get() by a call to PyDict_GetItem().
"""
if len(args) == 2:
args.append(ExprNodes.NoneNode(node.pos))
elif len(args) != 3:
self._error_wrong_arg_count('dict.get', node, args, "2 or 3")
return node
return self._substitute_method_call(
node, "__Pyx_PyDict_GetItemDefault", self.Pyx_PyDict_GetItem_func_type,
'get', is_unbound_method, args,
may_return_none = True,
utility_code = dict_getitem_default_utility_code)
### unicode type methods
PyUnicode_uchar_predicate_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_bint_type, [
PyrexTypes.CFuncTypeArg("uchar", PyrexTypes.c_py_unicode_type, None),
])
def _inject_unicode_predicate(self, node, args, is_unbound_method):
if is_unbound_method or len(args) != 1:
return node
ustring = args[0]
if not isinstance(ustring, ExprNodes.CoerceToPyTypeNode) or \
ustring.arg.type is not PyrexTypes.c_py_unicode_type:
return node
uchar = ustring.arg
method_name = node.function.attribute
if method_name == 'istitle':
# istitle() doesn't directly map to Py_UNICODE_ISTITLE()
utility_code = py_unicode_istitle_utility_code
function_name = '__Pyx_Py_UNICODE_ISTITLE'
else:
utility_code = None
function_name = 'Py_UNICODE_%s' % method_name.upper()
func_call = self._substitute_method_call(
node, function_name, self.PyUnicode_uchar_predicate_func_type,
method_name, is_unbound_method, [uchar],
utility_code = utility_code)
if node.type.is_pyobject:
func_call = func_call.coerce_to_pyobject(self.current_env)
return func_call
_handle_simple_method_unicode_isalnum = _inject_unicode_predicate
_handle_simple_method_unicode_isalpha = _inject_unicode_predicate
_handle_simple_method_unicode_isdecimal = _inject_unicode_predicate
_handle_simple_method_unicode_isdigit = _inject_unicode_predicate
_handle_simple_method_unicode_islower = _inject_unicode_predicate
_handle_simple_method_unicode_isnumeric = _inject_unicode_predicate
_handle_simple_method_unicode_isspace = _inject_unicode_predicate
_handle_simple_method_unicode_istitle = _inject_unicode_predicate
_handle_simple_method_unicode_isupper = _inject_unicode_predicate
PyUnicode_uchar_conversion_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_py_unicode_type, [
PyrexTypes.CFuncTypeArg("uchar", PyrexTypes.c_py_unicode_type, None),
])
def _inject_unicode_character_conversion(self, node, args, is_unbound_method):
if is_unbound_method or len(args) != 1:
return node
ustring = args[0]
if not isinstance(ustring, ExprNodes.CoerceToPyTypeNode) or \
ustring.arg.type is not PyrexTypes.c_py_unicode_type:
return node
uchar = ustring.arg
method_name = node.function.attribute
function_name = 'Py_UNICODE_TO%s' % method_name.upper()
func_call = self._substitute_method_call(
node, function_name, self.PyUnicode_uchar_conversion_func_type,
method_name, is_unbound_method, [uchar])
if node.type.is_pyobject:
func_call = func_call.coerce_to_pyobject(self.current_env)
return func_call
_handle_simple_method_unicode_lower = _inject_unicode_character_conversion
_handle_simple_method_unicode_upper = _inject_unicode_character_conversion
_handle_simple_method_unicode_title = _inject_unicode_character_conversion
PyUnicode_Splitlines_func_type = PyrexTypes.CFuncType(
Builtin.list_type, [
PyrexTypes.CFuncTypeArg("str", Builtin.unicode_type, None),
PyrexTypes.CFuncTypeArg("keepends", PyrexTypes.c_bint_type, None),
])
def _handle_simple_method_unicode_splitlines(self, node, args, is_unbound_method):
"""Replace unicode.splitlines(...) by a direct call to the
corresponding C-API function.
"""
if len(args) not in (1,2):
self._error_wrong_arg_count('unicode.splitlines', node, args, "1 or 2")
return node
self._inject_bint_default_argument(node, args, 1, False)
return self._substitute_method_call(
node, "PyUnicode_Splitlines", self.PyUnicode_Splitlines_func_type,
'splitlines', is_unbound_method, args)
PyUnicode_Join_func_type = PyrexTypes.CFuncType(
Builtin.unicode_type, [
PyrexTypes.CFuncTypeArg("sep", Builtin.unicode_type, None),
PyrexTypes.CFuncTypeArg("iterable", PyrexTypes.py_object_type, None),
])
def _handle_simple_method_unicode_join(self, node, args, is_unbound_method):
"""Replace unicode.join(...) by a direct call to the
corresponding C-API function.
"""
if len(args) != 2:
self._error_wrong_arg_count('unicode.join', node, args, 2)
return node
return self._substitute_method_call(
node, "PyUnicode_Join", self.PyUnicode_Join_func_type,
'join', is_unbound_method, args)
PyUnicode_Split_func_type = PyrexTypes.CFuncType(
Builtin.list_type, [
PyrexTypes.CFuncTypeArg("str", Builtin.unicode_type, None),
PyrexTypes.CFuncTypeArg("sep", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("maxsplit", PyrexTypes.c_py_ssize_t_type, None),
]
)
def _handle_simple_method_unicode_split(self, node, args, is_unbound_method):
"""Replace unicode.split(...) by a direct call to the
corresponding C-API function.
"""
if len(args) not in (1,2,3):
self._error_wrong_arg_count('unicode.split', node, args, "1-3")
return node
if len(args) < 2:
args.append(ExprNodes.NullNode(node.pos))
self._inject_int_default_argument(
node, args, 2, PyrexTypes.c_py_ssize_t_type, "-1")
return self._substitute_method_call(
node, "PyUnicode_Split", self.PyUnicode_Split_func_type,
'split', is_unbound_method, args)
PyUnicode_Tailmatch_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_bint_type, [
PyrexTypes.CFuncTypeArg("str", Builtin.unicode_type, None),
PyrexTypes.CFuncTypeArg("substring", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("start", PyrexTypes.c_py_ssize_t_type, None),
PyrexTypes.CFuncTypeArg("end", PyrexTypes.c_py_ssize_t_type, None),
PyrexTypes.CFuncTypeArg("direction", PyrexTypes.c_int_type, None),
],
exception_value = '-1')
def _handle_simple_method_unicode_endswith(self, node, args, is_unbound_method):
return self._inject_unicode_tailmatch(
node, args, is_unbound_method, 'endswith', +1)
def _handle_simple_method_unicode_startswith(self, node, args, is_unbound_method):
return self._inject_unicode_tailmatch(
node, args, is_unbound_method, 'startswith', -1)
def _inject_unicode_tailmatch(self, node, args, is_unbound_method,
method_name, direction):
"""Replace unicode.startswith(...) and unicode.endswith(...)
by a direct call to the corresponding C-API function.
"""
if len(args) not in (2,3,4):
self._error_wrong_arg_count('unicode.%s' % method_name, node, args, "2-4")
return node
self._inject_int_default_argument(
node, args, 2, PyrexTypes.c_py_ssize_t_type, "0")
self._inject_int_default_argument(
node, args, 3, PyrexTypes.c_py_ssize_t_type, "PY_SSIZE_T_MAX")
args.append(ExprNodes.IntNode(
node.pos, value=str(direction), type=PyrexTypes.c_int_type))
method_call = self._substitute_method_call(
node, "__Pyx_PyUnicode_Tailmatch", self.PyUnicode_Tailmatch_func_type,
method_name, is_unbound_method, args,
utility_code = unicode_tailmatch_utility_code)
return method_call.coerce_to(Builtin.bool_type, self.current_env())
PyUnicode_Find_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_py_ssize_t_type, [
PyrexTypes.CFuncTypeArg("str", Builtin.unicode_type, None),
PyrexTypes.CFuncTypeArg("substring", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("start", PyrexTypes.c_py_ssize_t_type, None),
PyrexTypes.CFuncTypeArg("end", PyrexTypes.c_py_ssize_t_type, None),
PyrexTypes.CFuncTypeArg("direction", PyrexTypes.c_int_type, None),
],
exception_value = '-2')
def _handle_simple_method_unicode_find(self, node, args, is_unbound_method):
return self._inject_unicode_find(
node, args, is_unbound_method, 'find', +1)
def _handle_simple_method_unicode_rfind(self, node, args, is_unbound_method):
return self._inject_unicode_find(
node, args, is_unbound_method, 'rfind', -1)
def _inject_unicode_find(self, node, args, is_unbound_method,
method_name, direction):
"""Replace unicode.find(...) and unicode.rfind(...) by a
direct call to the corresponding C-API function.
"""
if len(args) not in (2,3,4):
self._error_wrong_arg_count('unicode.%s' % method_name, node, args, "2-4")
return node
self._inject_int_default_argument(
node, args, 2, PyrexTypes.c_py_ssize_t_type, "0")
self._inject_int_default_argument(
node, args, 3, PyrexTypes.c_py_ssize_t_type, "PY_SSIZE_T_MAX")
args.append(ExprNodes.IntNode(
node.pos, value=str(direction), type=PyrexTypes.c_int_type))
method_call = self._substitute_method_call(
node, "PyUnicode_Find", self.PyUnicode_Find_func_type,
method_name, is_unbound_method, args)
return method_call.coerce_to_pyobject(self.current_env())
PyUnicode_Count_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_py_ssize_t_type, [
PyrexTypes.CFuncTypeArg("str", Builtin.unicode_type, None),
PyrexTypes.CFuncTypeArg("substring", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("start", PyrexTypes.c_py_ssize_t_type, None),
PyrexTypes.CFuncTypeArg("end", PyrexTypes.c_py_ssize_t_type, None),
],
exception_value = '-1')
def _handle_simple_method_unicode_count(self, node, args, is_unbound_method):
"""Replace unicode.count(...) by a direct call to the
corresponding C-API function.
"""
if len(args) not in (2,3,4):
self._error_wrong_arg_count('unicode.count', node, args, "2-4")
return node
self._inject_int_default_argument(
node, args, 2, PyrexTypes.c_py_ssize_t_type, "0")
self._inject_int_default_argument(
node, args, 3, PyrexTypes.c_py_ssize_t_type, "PY_SSIZE_T_MAX")
method_call = self._substitute_method_call(
node, "PyUnicode_Count", self.PyUnicode_Count_func_type,
'count', is_unbound_method, args)
return method_call.coerce_to_pyobject(self.current_env())
PyUnicode_Replace_func_type = PyrexTypes.CFuncType(
Builtin.unicode_type, [
PyrexTypes.CFuncTypeArg("str", Builtin.unicode_type, None),
PyrexTypes.CFuncTypeArg("substring", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("replstr", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("maxcount", PyrexTypes.c_py_ssize_t_type, None),
])
def _handle_simple_method_unicode_replace(self, node, args, is_unbound_method):
"""Replace unicode.replace(...) by a direct call to the
corresponding C-API function.
"""
if len(args) not in (3,4):
self._error_wrong_arg_count('unicode.replace', node, args, "3-4")
return node
self._inject_int_default_argument(
node, args, 3, PyrexTypes.c_py_ssize_t_type, "-1")
return self._substitute_method_call(
node, "PyUnicode_Replace", self.PyUnicode_Replace_func_type,
'replace', is_unbound_method, args)
PyUnicode_AsEncodedString_func_type = PyrexTypes.CFuncType(
Builtin.bytes_type, [
PyrexTypes.CFuncTypeArg("obj", Builtin.unicode_type, None),
PyrexTypes.CFuncTypeArg("encoding", PyrexTypes.c_char_ptr_type, None),
PyrexTypes.CFuncTypeArg("errors", PyrexTypes.c_char_ptr_type, None),
])
PyUnicode_AsXyzString_func_type = PyrexTypes.CFuncType(
Builtin.bytes_type, [
PyrexTypes.CFuncTypeArg("obj", Builtin.unicode_type, None),
])
_special_encodings = ['UTF8', 'UTF16', 'Latin1', 'ASCII',
'unicode_escape', 'raw_unicode_escape']
_special_codecs = [ (name, codecs.getencoder(name))
for name in _special_encodings ]
def _handle_simple_method_unicode_encode(self, node, args, is_unbound_method):
"""Replace unicode.encode(...) by a direct C-API call to the
corresponding codec.
"""
if len(args) < 1 or len(args) > 3:
self._error_wrong_arg_count('unicode.encode', node, args, '1-3')
return node
string_node = args[0]
if len(args) == 1:
null_node = ExprNodes.NullNode(node.pos)
return self._substitute_method_call(
node, "PyUnicode_AsEncodedString",
self.PyUnicode_AsEncodedString_func_type,
'encode', is_unbound_method, [string_node, null_node, null_node])
parameters = self._unpack_encoding_and_error_mode(node.pos, args)
if parameters is None:
return node
encoding, encoding_node, error_handling, error_handling_node = parameters
if isinstance(string_node, ExprNodes.UnicodeNode):
# constant, so try to do the encoding at compile time
try:
value = string_node.value.encode(encoding, error_handling)
except:
# well, looks like we can't
pass
else:
value = BytesLiteral(value)
value.encoding = encoding
return ExprNodes.BytesNode(
string_node.pos, value=value, type=Builtin.bytes_type)
if error_handling == 'strict':
# try to find a specific encoder function
codec_name = self._find_special_codec_name(encoding)
if codec_name is not None:
encode_function = "PyUnicode_As%sString" % codec_name
return self._substitute_method_call(
node, encode_function,
self.PyUnicode_AsXyzString_func_type,
'encode', is_unbound_method, [string_node])
return self._substitute_method_call(
node, "PyUnicode_AsEncodedString",
self.PyUnicode_AsEncodedString_func_type,
'encode', is_unbound_method,
[string_node, encoding_node, error_handling_node])
PyUnicode_DecodeXyz_func_type = PyrexTypes.CFuncType(
Builtin.unicode_type, [
PyrexTypes.CFuncTypeArg("string", PyrexTypes.c_char_ptr_type, None),
PyrexTypes.CFuncTypeArg("size", PyrexTypes.c_py_ssize_t_type, None),
PyrexTypes.CFuncTypeArg("errors", PyrexTypes.c_char_ptr_type, None),
])
PyUnicode_Decode_func_type = PyrexTypes.CFuncType(
Builtin.unicode_type, [
PyrexTypes.CFuncTypeArg("string", PyrexTypes.c_char_ptr_type, None),
PyrexTypes.CFuncTypeArg("size", PyrexTypes.c_py_ssize_t_type, None),
PyrexTypes.CFuncTypeArg("encoding", PyrexTypes.c_char_ptr_type, None),
PyrexTypes.CFuncTypeArg("errors", PyrexTypes.c_char_ptr_type, None),
])
def _handle_simple_method_bytes_decode(self, node, args, is_unbound_method):
"""Replace char*.decode() by a direct C-API call to the
corresponding codec, possibly resoving a slice on the char*.
"""
if len(args) < 1 or len(args) > 3:
self._error_wrong_arg_count('bytes.decode', node, args, '1-3')
return node
temps = []
if isinstance(args[0], ExprNodes.SliceIndexNode):
index_node = args[0]
string_node = index_node.base
if not string_node.type.is_string:
# nothing to optimise here
return node
start, stop = index_node.start, index_node.stop
if not start or start.constant_result == 0:
start = None
else:
if start.type.is_pyobject:
start = start.coerce_to(PyrexTypes.c_py_ssize_t_type, self.current_env())
if stop:
start = UtilNodes.LetRefNode(start)
temps.append(start)
string_node = ExprNodes.AddNode(pos=start.pos,
operand1=string_node,
operator='+',
operand2=start,
is_temp=False,
type=string_node.type
)
if stop and stop.type.is_pyobject:
stop = stop.coerce_to(PyrexTypes.c_py_ssize_t_type, self.current_env())
elif isinstance(args[0], ExprNodes.CoerceToPyTypeNode) \
and args[0].arg.type.is_string:
# use strlen() to find the string length, just as CPython would
start = stop = None
string_node = args[0].arg
else:
# let Python do its job
return node
if not stop:
if start or not string_node.is_name:
string_node = UtilNodes.LetRefNode(string_node)
temps.append(string_node)
stop = ExprNodes.PythonCapiCallNode(
string_node.pos, "strlen", self.Pyx_strlen_func_type,
args = [string_node],
is_temp = False,
utility_code = include_string_h_utility_code,
).coerce_to(PyrexTypes.c_py_ssize_t_type, self.current_env())
elif start:
stop = ExprNodes.SubNode(
pos = stop.pos,
operand1 = stop,
operator = '-',
operand2 = start,
is_temp = False,
type = PyrexTypes.c_py_ssize_t_type
)
parameters = self._unpack_encoding_and_error_mode(node.pos, args)
if parameters is None:
return node
encoding, encoding_node, error_handling, error_handling_node = parameters
# try to find a specific encoder function
codec_name = None
if encoding is not None:
codec_name = self._find_special_codec_name(encoding)
if codec_name is not None:
decode_function = "PyUnicode_Decode%s" % codec_name
node = ExprNodes.PythonCapiCallNode(
node.pos, decode_function,
self.PyUnicode_DecodeXyz_func_type,
args = [string_node, stop, error_handling_node],
is_temp = node.is_temp,
)
else:
node = ExprNodes.PythonCapiCallNode(
node.pos, "PyUnicode_Decode",
self.PyUnicode_Decode_func_type,
args = [string_node, stop, encoding_node, error_handling_node],
is_temp = node.is_temp,
)
for temp in temps[::-1]:
node = UtilNodes.EvalWithTempExprNode(temp, node)
return node
def _find_special_codec_name(self, encoding):
try:
requested_codec = codecs.getencoder(encoding)
except:
return None
for name, codec in self._special_codecs:
if codec == requested_codec:
if '_' in name:
name = ''.join([ s.capitalize()
for s in name.split('_')])
return name
return None
def _unpack_encoding_and_error_mode(self, pos, args):
null_node = ExprNodes.NullNode(pos)
if len(args) >= 2:
encoding_node = args[1]
if isinstance(encoding_node, ExprNodes.CoerceToPyTypeNode):
encoding_node = encoding_node.arg
if isinstance(encoding_node, (ExprNodes.UnicodeNode, ExprNodes.StringNode,
ExprNodes.BytesNode)):
encoding = encoding_node.value
encoding_node = ExprNodes.BytesNode(encoding_node.pos, value=encoding,
type=PyrexTypes.c_char_ptr_type)
elif encoding_node.type is Builtin.bytes_type:
encoding = None
encoding_node = encoding_node.coerce_to(
PyrexTypes.c_char_ptr_type, self.current_env())
elif encoding_node.type.is_string:
encoding = None
else:
return None
else:
encoding = None
encoding_node = null_node
if len(args) == 3:
error_handling_node = args[2]
if isinstance(error_handling_node, ExprNodes.CoerceToPyTypeNode):
error_handling_node = error_handling_node.arg
if isinstance(error_handling_node,
(ExprNodes.UnicodeNode, ExprNodes.StringNode,
ExprNodes.BytesNode)):
error_handling = error_handling_node.value
if error_handling == 'strict':
error_handling_node = null_node
else:
error_handling_node = ExprNodes.BytesNode(
error_handling_node.pos, value=error_handling,
type=PyrexTypes.c_char_ptr_type)
elif error_handling_node.type is Builtin.bytes_type:
error_handling = None
error_handling_node = error_handling_node.coerce_to(
PyrexTypes.c_char_ptr_type, self.current_env())
elif error_handling_node.type.is_string:
error_handling = None
else:
return None
else:
error_handling = 'strict'
error_handling_node = null_node
return (encoding, encoding_node, error_handling, error_handling_node)
### helpers
def _substitute_method_call(self, node, name, func_type,
attr_name, is_unbound_method, args=(),
utility_code=None,
may_return_none=ExprNodes.PythonCapiCallNode.may_return_none):
args = list(args)
if args and not args[0].is_literal:
self_arg = args[0]
if is_unbound_method:
self_arg = self_arg.as_none_safe_node(
"descriptor '%s' requires a '%s' object but received a 'NoneType'" % (
attr_name, node.function.obj.name))
else:
self_arg = self_arg.as_none_safe_node(
"'NoneType' object has no attribute '%s'" % attr_name,
error = "PyExc_AttributeError")
args[0] = self_arg
return ExprNodes.PythonCapiCallNode(
node.pos, name, func_type,
args = args,
is_temp = node.is_temp,
utility_code = utility_code,
may_return_none = may_return_none,
)
def _inject_int_default_argument(self, node, args, arg_index, type, default_value):
assert len(args) >= arg_index
if len(args) == arg_index:
args.append(ExprNodes.IntNode(node.pos, value=str(default_value),
type=type, constant_result=default_value))
else:
args[arg_index] = args[arg_index].coerce_to(type, self.current_env())
def _inject_bint_default_argument(self, node, args, arg_index, default_value):
assert len(args) >= arg_index
if len(args) == arg_index:
default_value = bool(default_value)
args.append(ExprNodes.BoolNode(node.pos, value=default_value,
constant_result=default_value))
else:
args[arg_index] = args[arg_index].coerce_to_boolean(self.current_env())
py_unicode_istitle_utility_code = UtilityCode(
# Py_UNICODE_ISTITLE() doesn't match unicode.istitle() as the latter
# additionally allows character that comply with Py_UNICODE_ISUPPER()
proto = '''
static CYTHON_INLINE int __Pyx_Py_UNICODE_ISTITLE(Py_UNICODE uchar); /* proto */
''',
impl = '''
static CYTHON_INLINE int __Pyx_Py_UNICODE_ISTITLE(Py_UNICODE uchar) {
return Py_UNICODE_ISTITLE(uchar) || Py_UNICODE_ISUPPER(uchar);
}
''')
unicode_tailmatch_utility_code = UtilityCode(
# Python's unicode.startswith() and unicode.endswith() support a
# tuple of prefixes/suffixes, whereas it's much more common to
# test for a single unicode string.
proto = '''
static int __Pyx_PyUnicode_Tailmatch(PyObject* s, PyObject* substr, \
Py_ssize_t start, Py_ssize_t end, int direction);
''',
impl = '''
static int __Pyx_PyUnicode_Tailmatch(PyObject* s, PyObject* substr,
Py_ssize_t start, Py_ssize_t end, int direction) {
if (unlikely(PyTuple_Check(substr))) {
int result;
Py_ssize_t i;
for (i = 0; i < PyTuple_GET_SIZE(substr); i++) {
result = PyUnicode_Tailmatch(s, PyTuple_GET_ITEM(substr, i),
start, end, direction);
if (result) {
return result;
}
}
return 0;
}
return PyUnicode_Tailmatch(s, substr, start, end, direction);
}
''',
)
dict_getitem_default_utility_code = UtilityCode(
proto = '''
static PyObject* __Pyx_PyDict_GetItemDefault(PyObject* d, PyObject* key, PyObject* default_value) {
PyObject* value;
#if PY_MAJOR_VERSION >= 3
value = PyDict_GetItemWithError(d, key);
if (unlikely(!value)) {
if (unlikely(PyErr_Occurred()))
return NULL;
value = default_value;
}
Py_INCREF(value);
#else
if (PyString_CheckExact(key) || PyUnicode_CheckExact(key) || PyInt_CheckExact(key)) {
/* these presumably have safe hash functions */
value = PyDict_GetItem(d, key);
if (unlikely(!value)) {
value = default_value;
}
Py_INCREF(value);
} else {
PyObject *m;
m = __Pyx_GetAttrString(d, "get");
if (!m) return NULL;
value = PyObject_CallFunctionObjArgs(m, key,
(default_value == Py_None) ? NULL : default_value, NULL);
Py_DECREF(m);
}
#endif
return value;
}
''',
impl = ""
)
append_utility_code = UtilityCode(
proto = """
static CYTHON_INLINE PyObject* __Pyx_PyObject_Append(PyObject* L, PyObject* x) {
if (likely(PyList_CheckExact(L))) {
if (PyList_Append(L, x) < 0) return NULL;
Py_INCREF(Py_None);
return Py_None; /* this is just to have an accurate signature */
}
else {
PyObject *r, *m;
m = __Pyx_GetAttrString(L, "append");
if (!m) return NULL;
r = PyObject_CallFunctionObjArgs(m, x, NULL);
Py_DECREF(m);
return r;
}
}
""",
impl = ""
)
pop_utility_code = UtilityCode(
proto = """
static CYTHON_INLINE PyObject* __Pyx_PyObject_Pop(PyObject* L) {
PyObject *r, *m;
#if PY_VERSION_HEX >= 0x02040000
if (likely(PyList_CheckExact(L))
/* Check that both the size is positive and no reallocation shrinking needs to be done. */
&& likely(PyList_GET_SIZE(L) > (((PyListObject*)L)->allocated >> 1))) {
Py_SIZE(L) -= 1;
return PyList_GET_ITEM(L, PyList_GET_SIZE(L));
}
#endif
m = __Pyx_GetAttrString(L, "pop");
if (!m) return NULL;
r = PyObject_CallObject(m, NULL);
Py_DECREF(m);
return r;
}
""",
impl = ""
)
pop_index_utility_code = UtilityCode(
proto = """
static PyObject* __Pyx_PyObject_PopIndex(PyObject* L, Py_ssize_t ix);
""",
impl = """
static PyObject* __Pyx_PyObject_PopIndex(PyObject* L, Py_ssize_t ix) {
PyObject *r, *m, *t, *py_ix;
#if PY_VERSION_HEX >= 0x02040000
if (likely(PyList_CheckExact(L))) {
Py_ssize_t size = PyList_GET_SIZE(L);
if (likely(size > (((PyListObject*)L)->allocated >> 1))) {
if (ix < 0) {
ix += size;
}
if (likely(0 <= ix && ix < size)) {
Py_ssize_t i;
PyObject* v = PyList_GET_ITEM(L, ix);
Py_SIZE(L) -= 1;
size -= 1;
for(i=ix; itp_as_number && Py_TYPE(obj)->tp_as_number->nb_float) {
return PyFloat_AsDouble(obj);
} else if (PyUnicode_CheckExact(obj) || PyBytes_CheckExact(obj)) {
#if PY_MAJOR_VERSION >= 3
float_value = PyFloat_FromString(obj);
#else
float_value = PyFloat_FromString(obj, 0);
#endif
} else {
PyObject* args = PyTuple_New(1);
if (unlikely(!args)) goto bad;
PyTuple_SET_ITEM(args, 0, obj);
float_value = PyObject_Call((PyObject*)&PyFloat_Type, args, 0);
PyTuple_SET_ITEM(args, 0, 0);
Py_DECREF(args);
}
if (likely(float_value)) {
double value = PyFloat_AS_DOUBLE(float_value);
Py_DECREF(float_value);
return value;
}
bad:
return (double)-1;
}
'''
)
bytes_index_utility_code = UtilityCode(
proto = """
static CYTHON_INLINE char __Pyx_PyBytes_GetItemInt(PyObject* unicode, Py_ssize_t index, int check_bounds); /* proto */
""",
impl = """
static CYTHON_INLINE char __Pyx_PyBytes_GetItemInt(PyObject* bytes, Py_ssize_t index, int check_bounds) {
if (check_bounds) {
if (unlikely(index >= PyBytes_GET_SIZE(bytes)) |
((index < 0) & unlikely(index < -PyBytes_GET_SIZE(bytes)))) {
PyErr_Format(PyExc_IndexError, "string index out of range");
return -1;
}
}
if (index < 0)
index += PyBytes_GET_SIZE(bytes);
return PyBytes_AS_STRING(bytes)[index];
}
"""
)
include_string_h_utility_code = UtilityCode(
proto = """
#include
"""
)
tpnew_utility_code = UtilityCode(
proto = """
static CYTHON_INLINE PyObject* __Pyx_tp_new(PyObject* type_obj) {
return (PyObject*) (((PyTypeObject*)(type_obj))->tp_new(
(PyTypeObject*)(type_obj), %(TUPLE)s, NULL));
}
""" % {'TUPLE' : Naming.empty_tuple}
)
class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations):
"""Calculate the result of constant expressions to store it in
``expr_node.constant_result``, and replace trivial cases by their
constant result.
"""
def _calculate_const(self, node):
if node.constant_result is not ExprNodes.constant_value_not_set:
return
# make sure we always set the value
not_a_constant = ExprNodes.not_a_constant
node.constant_result = not_a_constant
# check if all children are constant
children = self.visitchildren(node)
for child_result in children.itervalues():
if type(child_result) is list:
for child in child_result:
if getattr(child, 'constant_result', not_a_constant) is not_a_constant:
return
elif getattr(child_result, 'constant_result', not_a_constant) is not_a_constant:
return
# now try to calculate the real constant value
try:
node.calculate_constant_result()
# if node.constant_result is not ExprNodes.not_a_constant:
# print node.__class__.__name__, node.constant_result
except (ValueError, TypeError, KeyError, IndexError, AttributeError, ArithmeticError):
# ignore all 'normal' errors here => no constant result
pass
except Exception:
# this looks like a real error
import traceback, sys
traceback.print_exc(file=sys.stdout)
NODE_TYPE_ORDER = (ExprNodes.CharNode, ExprNodes.IntNode,
ExprNodes.LongNode, ExprNodes.FloatNode)
def _widest_node_class(self, *nodes):
try:
return self.NODE_TYPE_ORDER[
max(map(self.NODE_TYPE_ORDER.index, map(type, nodes)))]
except ValueError:
return None
def visit_ExprNode(self, node):
self._calculate_const(node)
return node
def visit_BoolBinopNode(self, node):
self._calculate_const(node)
if node.constant_result is ExprNodes.not_a_constant:
return node
if not node.operand1.is_literal or not node.operand2.is_literal:
# We calculate other constants to make them available to
# the compiler, but we only aggregate constant nodes
# recursively, so non-const nodes are straight out.
return node
if node.constant_result == node.operand1.constant_result and node.operand1.is_literal:
return node.operand1
elif node.constant_result == node.operand2.constant_result and node.operand2.is_literal:
return node.operand2
else:
# FIXME: we could do more ...
return node
def visit_BinopNode(self, node):
self._calculate_const(node)
if node.constant_result is ExprNodes.not_a_constant:
return node
if isinstance(node.constant_result, float):
# We calculate float constants to make them available to
# the compiler, but we do not aggregate them into a
# constant node to prevent any loss of precision.
return node
if not node.operand1.is_literal or not node.operand2.is_literal:
# We calculate other constants to make them available to
# the compiler, but we only aggregate constant nodes
# recursively, so non-const nodes are straight out.
return node
# now inject a new constant node with the calculated value
try:
type1, type2 = node.operand1.type, node.operand2.type
if type1 is None or type2 is None:
return node
except AttributeError:
return node
if type1 is type2:
new_node = node.operand1
else:
widest_type = PyrexTypes.widest_numeric_type(type1, type2)
if type(node.operand1) is type(node.operand2):
new_node = node.operand1
new_node.type = widest_type
elif type1 is widest_type:
new_node = node.operand1
elif type2 is widest_type:
new_node = node.operand2
else:
target_class = self._widest_node_class(
node.operand1, node.operand2)
if target_class is None:
return node
new_node = target_class(pos=node.pos, type = widest_type)
new_node.constant_result = node.constant_result
if isinstance(node, ExprNodes.BoolNode):
new_node.value = node.constant_result
else:
new_node.value = str(node.constant_result)
#new_node = new_node.coerce_to(node.type, self.current_scope)
return new_node
def visit_PrimaryCmpNode(self, node):
self._calculate_const(node)
if node.constant_result is ExprNodes.not_a_constant:
return node
bool_result = bool(node.constant_result)
return ExprNodes.BoolNode(node.pos, value=bool_result,
constant_result=bool_result)
def visit_IfStatNode(self, node):
self.visitchildren(node)
# eliminate dead code based on constant condition results
if_clauses = []
for if_clause in node.if_clauses:
condition_result = if_clause.get_constant_condition_result()
if condition_result is None:
# unknown result => normal runtime evaluation
if_clauses.append(if_clause)
elif condition_result == True:
# subsequent clauses can safely be dropped
node.else_clause = if_clause.body
break
else:
assert condition_result == False
if not if_clauses:
return node.else_clause
node.if_clauses = if_clauses
return node
# in the future, other nodes can have their own handler method here
# that can replace them with a constant result node
visit_Node = Visitor.VisitorTransform.recurse_to_children
class FinalOptimizePhase(Visitor.CythonTransform):
"""
This visitor handles several commuting optimizations, and is run
just before the C code generation phase.
The optimizations currently implemented in this class are:
- eliminate None assignment and refcounting for first assignment.
- isinstance -> typecheck for cdef types
- eliminate checks for None and/or types that became redundant after tree changes
"""
def visit_SingleAssignmentNode(self, node):
"""Avoid redundant initialisation of local variables before their
first assignment.
"""
self.visitchildren(node)
if node.first:
lhs = node.lhs
lhs.lhs_of_first_assignment = True
if isinstance(lhs, ExprNodes.NameNode) and lhs.entry.type.is_pyobject:
# Have variable initialized to 0 rather than None
lhs.entry.init_to_none = False
lhs.entry.init = 0
return node
def visit_SimpleCallNode(self, node):
"""Replace generic calls to isinstance(x, type) by a more efficient
type check.
"""
self.visitchildren(node)
if node.function.type.is_cfunction and isinstance(node.function, ExprNodes.NameNode):
if node.function.name == 'isinstance':
type_arg = node.args[1]
if type_arg.type.is_builtin_type and type_arg.type.name == 'type':
from CythonScope import utility_scope
node.function.entry = utility_scope.lookup('PyObject_TypeCheck')
node.function.type = node.function.entry.type
PyTypeObjectPtr = PyrexTypes.CPtrType(utility_scope.lookup('PyTypeObject').type)
node.args[1] = ExprNodes.CastNode(node.args[1], PyTypeObjectPtr)
return node
def visit_PyTypeTestNode(self, node):
"""Remove tests for alternatively allowed None values from
type tests when we know that the argument cannot be None
anyway.
"""
self.visitchildren(node)
if not node.notnone:
if not node.arg.may_be_none():
node.notnone = True
return node
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Options.py 0000664 0000000 0000000 00000013425 11446142532 0024774 0 ustar 00root root 0000000 0000000 #
# Cython - Compilation-wide options and pragma declarations
#
cache_builtins = 1 # Perform lookups on builtin names only once
embed_pos_in_docstring = 0
gcc_branch_hints = 1
pre_import = None
docstrings = True
# Decref global variables in this module on exit for garbage collection.
# 0: None, 1+: interned objects, 2+: cdef globals, 3+: types objects
# Mostly for reducing noise for Valgrind, only executes at process exit
# (when all memory will be reclaimed anyways).
generate_cleanup_code = 0
annotate = 0
# This will convert statements of the form "for i in range(...)"
# to "for i from ..." when i is a cdef'd 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, wheras without this option the loop
# will execute until an overflowing value is encountered.
convert_range = 1
# 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 0 it simply creates a wrapper.
lookup_module_cpdef = 0
# This will set local variables to None rather than NULL which may cause
# surpress what would be an UnboundLocalError in pure Python but eliminates
# checking for NULL on every use, and can decref rather than xdecref at the end.
# WARNING: This is a work in progress, may currently segfault.
init_local_none = 1
# Append the c file and line number to the traceback for exceptions.
c_line_in_traceback = 1
# Whether or not to embed the Python interpreter, for use in making a
# standalone executable. This will provide a main() method which simply
# executes the body of this module.
embed = False
# Declare compiler directives
directive_defaults = {
'boundscheck' : True,
'nonecheck' : False,
'embedsignature' : False,
'locals' : {},
'auto_cpdef': False,
'cdivision': False, # was True before 0.12
'cdivision_warnings': False,
'always_allow_keywords': False,
'allow_none_for_extension_args': True,
'wraparound' : True,
'ccomplex' : False, # use C99/C++ for complex types and arith
'callspec' : "",
'profile': False,
'infer_types': None,
'infer_types.verbose': False,
'autotestdict': True,
'language_level': 2,
'warn': None,
'warn.undeclared': False,
# test support
'test_assert_path_exists' : [],
'test_fail_if_path_exists' : [],
# experimental, subject to change
'binding': False,
}
# Override types possibilities above, if needed
directive_types = {
'infer_types' : bool, # values can be True/None/False
}
for key, val in directive_defaults.items():
if key not in directive_types:
directive_types[key] = type(val)
directive_scopes = { # defaults to available everywhere
# 'module', 'function', 'class', 'with statement'
'autotestdict' : ('module',),
'test_assert_path_exists' : ('function',),
'test_fail_if_path_exists' : ('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')
None
>>> parse_directive_value('boundscheck', 'True')
True
>>> parse_directive_value('boundscheck', 'true')
Traceback (most recent call last):
...
ValueError: boundscheck directive must be set to True or False, got 'true'
"""
type = directive_types.get(name)
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 relaxed_bool:
value = value.lower()
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:
try:
return int(value)
except ValueError:
raise ValueError("%s directive must be set to an integer, got '%s'" % (
name, orig_value))
elif type is str:
return str(value)
else:
assert False
def parse_directive_list(s, relaxed_bool=False, ignore_unknown=False,
current_settings=None):
"""
Parses a comma-separated list of pragma options. Whitespace
is not considered.
>>> parse_directive_list(' ')
{}
>>> (parse_directive_list('boundscheck=True') ==
... {'boundscheck': True})
True
>>> parse_directive_list(' asdf')
Traceback (most recent call last):
...
ValueError: Expected "=" in option "asdf"
>>> parse_directive_list('boundscheck=hey')
Traceback (most recent call last):
...
ValueError: boundscheck directive must be set to True or False, got 'hey'
>>> parse_directive_list('unknown=True')
Traceback (most recent call last):
...
ValueError: Unknown option: "unknown"
"""
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.strip().split('=', 1) ]
parsed_value = parse_directive_value(name, value, relaxed_bool=relaxed_bool)
if parsed_value is None:
if not ignore_unknown:
raise ValueError('Unknown option: "%s"' % name)
else:
result[name] = parsed_value
return result
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/ParseTreeTransforms.py 0000664 0000000 0000000 00000166345 11446142532 0027324 0 ustar 00root root 0000000 0000000 from Cython.Compiler.Visitor import VisitorTransform, TreeVisitor
from Cython.Compiler.Visitor import CythonTransform, EnvTransform
from Cython.Compiler.ModuleNode import ModuleNode
from Cython.Compiler.Nodes import *
from Cython.Compiler.ExprNodes import *
from Cython.Compiler.UtilNodes import *
from Cython.Compiler.TreeFragment import TreeFragment, TemplateTransform
from Cython.Compiler.StringEncoding import EncodedString
from Cython.Compiler.Errors import error, CompileError
from Cython.Compiler import Errors
try:
set
except NameError:
from sets import Set as set
import copy
import os
import errno
try:
from lxml import etree
have_lxml = True
except ImportError:
have_lxml = False
try:
# Python 2.5
from xml.etree import cElementTree as etree
except ImportError:
try:
# Python 2.5
from xml.etree import ElementTree as etree
except ImportError:
try:
# normal cElementTree install
import cElementTree as etree
except ImportError:
try:
# normal ElementTree install
import elementtree.ElementTree as etree
except ImportError:
etree = None
class NameNodeCollector(TreeVisitor):
"""Collect all NameNodes of a (sub-)tree in the ``name_nodes``
attribute.
"""
def __init__(self):
super(NameNodeCollector, self).__init__()
self.name_nodes = []
visit_Node = TreeVisitor.visitchildren
def visit_NameNode(self, node):
self.name_nodes.append(node)
class SkipDeclarations(object):
"""
Variable and function declarations can often have a deep tree structure,
and yet most transformations don't need to descend to this depth.
Declaration nodes are removed after AnalyseDeclarationsTransform, so there
is no need to use this for transformations after that point.
"""
def visit_CTypeDefNode(self, node):
return node
def visit_CVarDefNode(self, node):
return node
def visit_CDeclaratorNode(self, node):
return node
def visit_CBaseTypeNode(self, node):
return node
def visit_CEnumDefNode(self, node):
return node
def visit_CStructOrUnionDefNode(self, node):
return node
class NormalizeTree(CythonTransform):
"""
This transform fixes up a few things after parsing
in order to make the parse tree more suitable for
transforms.
a) After parsing, blocks with only one statement will
be represented by that statement, not by a StatListNode.
When doing transforms this is annoying and inconsistent,
as one cannot in general remove a statement in a consistent
way and so on. This transform wraps any single statements
in a StatListNode containing a single statement.
b) The PassStatNode is a noop and serves no purpose beyond
plugging such one-statement blocks; i.e., once parsed a
` "pass" can just as well be represented using an empty
StatListNode. This means less special cases to worry about
in subsequent transforms (one always checks to see if a
StatListNode has no children to see if the block is empty).
"""
def __init__(self, context):
super(NormalizeTree, self).__init__(context)
self.is_in_statlist = False
self.is_in_expr = False
def visit_ExprNode(self, node):
stacktmp = self.is_in_expr
self.is_in_expr = True
self.visitchildren(node)
self.is_in_expr = stacktmp
return node
def visit_StatNode(self, node, is_listcontainer=False):
stacktmp = self.is_in_statlist
self.is_in_statlist = is_listcontainer
self.visitchildren(node)
self.is_in_statlist = stacktmp
if not self.is_in_statlist and not self.is_in_expr:
return StatListNode(pos=node.pos, stats=[node])
else:
return node
def visit_StatListNode(self, node):
self.is_in_statlist = True
self.visitchildren(node)
self.is_in_statlist = False
return node
def visit_ParallelAssignmentNode(self, node):
return self.visit_StatNode(node, True)
def visit_CEnumDefNode(self, node):
return self.visit_StatNode(node, True)
def visit_CStructOrUnionDefNode(self, node):
return self.visit_StatNode(node, True)
# Eliminate PassStatNode
def visit_PassStatNode(self, node):
if not self.is_in_statlist:
return StatListNode(pos=node.pos, stats=[])
else:
return []
def visit_CDeclaratorNode(self, node):
return node
class PostParseError(CompileError): pass
# error strings checked by unit tests, so define them
ERR_CDEF_INCLASS = 'Cannot assign default value to fields in cdef classes, structs or unions'
ERR_BUF_DEFAULTS = 'Invalid buffer defaults specification (see docs)'
ERR_INVALID_SPECIALATTR_TYPE = 'Special attributes must not have a type declared'
class PostParse(CythonTransform):
"""
Basic interpretation of the parse tree, as well as validity
checking that can be done on a very basic level on the parse
tree (while still not being a problem with the basic syntax,
as such).
Specifically:
- Default values to cdef assignments are turned into single
assignments following the declaration (everywhere but in class
bodies, where they raise a compile error)
- Interpret some node structures into Python runtime values.
Some nodes take compile-time arguments (currently:
TemplatedTypeNode[args] and __cythonbufferdefaults__ = {args}),
which should be interpreted. This happens in a general way
and other steps should be taken to ensure validity.
Type arguments cannot be interpreted in this way.
- For __cythonbufferdefaults__ the arguments are checked for
validity.
TemplatedTypeNode has its directives interpreted:
Any first positional argument goes into the "dtype" attribute,
any "ndim" keyword argument goes into the "ndim" attribute and
so on. Also it is checked that the directive combination is valid.
- __cythonbufferdefaults__ attributes are parsed and put into the
type information.
Note: Currently Parsing.py does a lot of interpretation and
reorganization that can be refactored into this transform
if a more pure Abstract Syntax Tree is wanted.
"""
# Track our context.
scope_type = None # can be either of 'module', 'function', 'class'
def __init__(self, context):
super(PostParse, self).__init__(context)
self.specialattribute_handlers = {
'__cythonbufferdefaults__' : self.handle_bufferdefaults
}
def visit_ModuleNode(self, node):
self.scope_type = 'module'
self.scope_node = node
self.lambda_counter = 1
self.visitchildren(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.visitchildren(node)
self.scope_type, self.scope_node = prev
return node
def visit_ClassDefNode(self, node):
return self.visit_scope(node, 'class')
def visit_FuncDefNode(self, node):
return self.visit_scope(node, 'function')
def visit_CStructOrUnionDefNode(self, node):
return self.visit_scope(node, 'struct')
def visit_LambdaNode(self, node):
# unpack a lambda expression into the corresponding DefNode
if self.scope_type != 'function':
error(node.pos,
"lambda functions are currently only supported in functions")
lambda_id = self.lambda_counter
self.lambda_counter += 1
node.lambda_name = EncodedString(u'lambda%d' % lambda_id)
body = Nodes.ReturnStatNode(
node.result_expr.pos, value = node.result_expr)
node.def_node = Nodes.DefNode(
node.pos, name=node.name, lambda_name=node.lambda_name,
args=node.args, star_arg=node.star_arg,
starstar_arg=node.starstar_arg,
body=body)
self.visitchildren(node)
return node
# cdef variables
def handle_bufferdefaults(self, decl):
if not isinstance(decl.default, DictNode):
raise PostParseError(decl.pos, ERR_BUF_DEFAULTS)
self.scope_node.buffer_defaults_node = decl.default
self.scope_node.buffer_defaults_pos = decl.pos
def visit_CVarDefNode(self, node):
# This assumes only plain names and pointers are assignable on
# declaration. Also, it makes use of the fact that a cdef decl
# must appear before the first use, so we don't have to deal with
# "i = 3; cdef int i = i" and can simply move the nodes around.
try:
self.visitchildren(node)
stats = [node]
newdecls = []
for decl in node.declarators:
declbase = decl
while isinstance(declbase, CPtrDeclaratorNode):
declbase = declbase.base
if isinstance(declbase, CNameDeclaratorNode):
if declbase.default is not None:
if self.scope_type in ('class', 'struct'):
if isinstance(self.scope_node, CClassDefNode):
handler = self.specialattribute_handlers.get(decl.name)
if handler:
if decl is not declbase:
raise PostParseError(decl.pos, ERR_INVALID_SPECIALATTR_TYPE)
handler(decl)
continue # Remove declaration
raise PostParseError(decl.pos, ERR_CDEF_INCLASS)
first_assignment = self.scope_type != 'module'
stats.append(SingleAssignmentNode(node.pos,
lhs=NameNode(node.pos, name=declbase.name),
rhs=declbase.default, first=first_assignment))
declbase.default = None
newdecls.append(decl)
node.declarators = newdecls
return stats
except PostParseError, 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)
return None
# Split parallel assignments (a,b = b,a) into separate partial
# assignments that are executed rhs-first using temps. This
# optimisation is best applied before type analysis so that known
# types on rhs and lhs can be matched directly.
def visit_SingleAssignmentNode(self, node):
self.visitchildren(node)
return self._visit_assignment_node(node, [node.lhs, node.rhs])
def visit_CascadedAssignmentNode(self, node):
self.visitchildren(node)
return self._visit_assignment_node(node, node.lhs_list + [node.rhs])
def _visit_assignment_node(self, node, expr_list):
"""Flatten parallel assignments into separate single
assignments or cascaded assignments.
"""
if sum([ 1 for expr in expr_list if expr.is_sequence_constructor ]) < 2:
# no parallel assignments => nothing to do
return node
expr_list_list = []
flatten_parallel_assignments(expr_list, expr_list_list)
temp_refs = []
eliminate_rhs_duplicates(expr_list_list, temp_refs)
nodes = []
for expr_list in expr_list_list:
lhs_list = expr_list[:-1]
rhs = expr_list[-1]
if len(lhs_list) == 1:
node = Nodes.SingleAssignmentNode(rhs.pos,
lhs = lhs_list[0], rhs = rhs)
else:
node = Nodes.CascadedAssignmentNode(rhs.pos,
lhs_list = lhs_list, rhs = rhs)
nodes.append(node)
if len(nodes) == 1:
assign_node = nodes[0]
else:
assign_node = Nodes.ParallelAssignmentNode(nodes[0].pos, stats = nodes)
if temp_refs:
duplicates_and_temps = [ (temp.expression, temp)
for temp in temp_refs ]
sort_common_subsequences(duplicates_and_temps)
for _, temp_ref in duplicates_and_temps[::-1]:
assign_node = LetNode(temp_ref, assign_node)
return assign_node
def eliminate_rhs_duplicates(expr_list_list, ref_node_sequence):
"""Replace rhs items by LetRefNodes if they appear more than once.
Creates a sequence of LetRefNodes that set up the required temps
and appends them to ref_node_sequence. The input list is modified
in-place.
"""
seen_nodes = set()
ref_nodes = {}
def find_duplicates(node):
if node.is_literal or node.is_name:
# no need to replace those; can't include attributes here
# as their access is not necessarily side-effect free
return
if node in seen_nodes:
if node not in ref_nodes:
ref_node = LetRefNode(node)
ref_nodes[node] = ref_node
ref_node_sequence.append(ref_node)
else:
seen_nodes.add(node)
if node.is_sequence_constructor:
for item in node.args:
find_duplicates(item)
for expr_list in expr_list_list:
rhs = expr_list[-1]
find_duplicates(rhs)
if not ref_nodes:
return
def substitute_nodes(node):
if node in ref_nodes:
return ref_nodes[node]
elif node.is_sequence_constructor:
node.args = map(substitute_nodes, node.args)
return node
# replace nodes inside of the common subexpressions
for node in ref_nodes:
if node.is_sequence_constructor:
node.args = map(substitute_nodes, node.args)
# replace common subexpressions on all rhs items
for expr_list in expr_list_list:
expr_list[-1] = substitute_nodes(expr_list[-1])
def sort_common_subsequences(items):
"""Sort items/subsequences so that all items and subsequences that
an item contains appear before the item itself. This implies a
partial order, and the sort must be stable to preserve the
original order as much as possible, so we use a simple insertion
sort.
"""
def contains(seq, x):
for item in seq:
if item is x:
return True
elif item.is_sequence_constructor and contains(item.args, x):
return True
return False
def lower_than(a,b):
return b.is_sequence_constructor and contains(b.args, a)
for pos, item in enumerate(items):
new_pos = pos
key = item[0]
for i in xrange(pos-1, -1, -1):
if lower_than(key, items[i][0]):
new_pos = i
if new_pos != pos:
for i in xrange(pos, new_pos, -1):
items[i] = items[i-1]
items[new_pos] = item
def flatten_parallel_assignments(input, output):
# The input is a list of expression nodes, representing the LHSs
# and RHS of one (possibly cascaded) assignment statement. For
# sequence constructors, rearranges the matching parts of both
# sides into a list of equivalent assignments between the
# individual elements. This transformation is applied
# recursively, so that nested structures get matched as well.
rhs = input[-1]
if not rhs.is_sequence_constructor or not sum([lhs.is_sequence_constructor for lhs in input[:-1]]):
output.append(input)
return
complete_assignments = []
rhs_size = len(rhs.args)
lhs_targets = [ [] for _ in xrange(rhs_size) ]
starred_assignments = []
for lhs in input[:-1]:
if not lhs.is_sequence_constructor:
if lhs.is_starred:
error(lhs.pos, "starred assignment target must be in a list or tuple")
complete_assignments.append(lhs)
continue
lhs_size = len(lhs.args)
starred_targets = sum([1 for expr in lhs.args if expr.is_starred])
if starred_targets > 1:
error(lhs.pos, "more than 1 starred expression in assignment")
output.append([lhs,rhs])
continue
elif lhs_size - starred_targets > rhs_size:
error(lhs.pos, "need more than %d value%s to unpack"
% (rhs_size, (rhs_size != 1) and 's' or ''))
output.append([lhs,rhs])
continue
elif starred_targets:
map_starred_assignment(lhs_targets, starred_assignments,
lhs.args, rhs.args)
elif lhs_size < rhs_size:
error(lhs.pos, "too many values to unpack (expected %d, got %d)"
% (lhs_size, rhs_size))
output.append([lhs,rhs])
continue
else:
for targets, expr in zip(lhs_targets, lhs.args):
targets.append(expr)
if complete_assignments:
complete_assignments.append(rhs)
output.append(complete_assignments)
# recursively flatten partial assignments
for cascade, rhs in zip(lhs_targets, rhs.args):
if cascade:
cascade.append(rhs)
flatten_parallel_assignments(cascade, output)
# recursively flatten starred assignments
for cascade in starred_assignments:
if cascade[0].is_sequence_constructor:
flatten_parallel_assignments(cascade, output)
else:
output.append(cascade)
def map_starred_assignment(lhs_targets, starred_assignments, lhs_args, rhs_args):
# Appends the fixed-position LHS targets to the target list that
# appear left and right of the starred argument.
#
# The starred_assignments list receives a new tuple
# (lhs_target, rhs_values_list) that maps the remaining arguments
# (those that match the starred target) to a list.
# left side of the starred target
for i, (targets, expr) in enumerate(zip(lhs_targets, lhs_args)):
if expr.is_starred:
starred = i
lhs_remaining = len(lhs_args) - i - 1
break
targets.append(expr)
else:
raise InternalError("no starred arg found when splitting starred assignment")
# right side of the starred target
for i, (targets, expr) in enumerate(zip(lhs_targets[-lhs_remaining:],
lhs_args[-lhs_remaining:])):
targets.append(expr)
# the starred target itself, must be assigned a (potentially empty) list
target = lhs_args[starred].target # unpack starred node
starred_rhs = rhs_args[starred:]
if lhs_remaining:
starred_rhs = starred_rhs[:-lhs_remaining]
if starred_rhs:
pos = starred_rhs[0].pos
else:
pos = target.pos
starred_assignments.append([
target, ExprNodes.ListNode(pos=pos, args=starred_rhs)])
class PxdPostParse(CythonTransform, SkipDeclarations):
"""
Basic interpretation/validity checking that should only be
done on pxd trees.
A lot of this checking currently happens in the parser; but
what is listed below happens here.
- "def" functions are let through only if they fill the
getbuffer/releasebuffer slots
- cdef functions are let through only if they are on the
top level and are declared "inline"
"""
ERR_INLINE_ONLY = "function definition in pxd file must be declared 'cdef inline'"
ERR_NOGO_WITH_INLINE = "inline function definition in pxd file cannot be '%s'"
def __call__(self, node):
self.scope_type = 'pxd'
return super(PxdPostParse, self).__call__(node)
def visit_CClassDefNode(self, node):
old = self.scope_type
self.scope_type = 'cclass'
self.visitchildren(node)
self.scope_type = old
return node
def visit_FuncDefNode(self, node):
# FuncDefNode always come with an implementation (without
# an imp they are CVarDefNodes..)
err = self.ERR_INLINE_ONLY
if (isinstance(node, DefNode) and self.scope_type == 'cclass'
and node.name in ('__getbuffer__', '__releasebuffer__')):
err = None # allow these slots
if isinstance(node, CFuncDefNode):
if u'inline' in node.modifiers and self.scope_type == 'pxd':
node.inline_in_pxd = True
if node.visibility != 'private':
err = self.ERR_NOGO_WITH_INLINE % node.visibility
elif node.api:
err = self.ERR_NOGO_WITH_INLINE % 'api'
else:
err = None # allow inline function
else:
err = self.ERR_INLINE_ONLY
if err:
self.context.nonfatal_error(PostParseError(node.pos, err))
return None
else:
return node
class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
"""
After parsing, directives can be stored in a number of places:
- #cython-comments at the top of the file (stored in ModuleNode)
- Command-line arguments overriding these
- @cython.directivename decorators
- with cython.directivename: statements
This transform is responsible for interpreting these various sources
and store the directive in two ways:
- Set the directives attribute of the ModuleNode for global directives.
- Use a CompilerDirectivesNode to override directives for a subtree.
(The first one is primarily to not have to modify with the tree
structure, so that ModuleNode stay on top.)
The directives are stored in dictionaries from name to value in effect.
Each such dictionary is always filled in for all possible directives,
using default values where no value is given by the user.
The available directives are controlled in Options.py.
Note that we have to run this prior to analysis, and so some minor
duplication of functionality has to occur: We manually track cimports
and which names the "cython" module may have been imported to.
"""
unop_method_nodes = {
'typeof': TypeofNode,
'operator.address': AmpersandNode,
'operator.dereference': DereferenceNode,
'operator.preincrement' : inc_dec_constructor(True, '++'),
'operator.predecrement' : inc_dec_constructor(True, '--'),
'operator.postincrement': inc_dec_constructor(False, '++'),
'operator.postdecrement': inc_dec_constructor(False, '--'),
# For backwards compatability.
'address': AmpersandNode,
}
binop_method_nodes = {
'operator.comma' : c_binop_constructor(','),
}
special_methods = set(['declare', 'union', 'struct', 'typedef', 'sizeof',
'cast', 'pointer', 'compiled', 'NULL']
+ unop_method_nodes.keys())
def __init__(self, context, compilation_directive_defaults):
super(InterpretCompilerDirectives, self).__init__(context)
self.compilation_directive_defaults = {}
for key, value in compilation_directive_defaults.iteritems():
self.compilation_directive_defaults[unicode(key)] = value
self.cython_module_names = set()
self.directive_names = {}
def check_directive_scope(self, pos, directive, scope):
legal_scopes = Options.directive_scopes.get(directive, None)
if legal_scopes and scope not in legal_scopes:
self.context.nonfatal_error(PostParseError(pos, 'The %s compiler directive '
'is not allowed in %s scope' % (directive, scope)))
return False
else:
return True
# Set up processing and handle the cython: comments.
def visit_ModuleNode(self, node):
for key, value in node.directive_comments.iteritems():
if not self.check_directive_scope(node.pos, key, 'module'):
self.wrong_scope_error(node.pos, key, 'module')
del node.directive_comments[key]
directives = copy.copy(Options.directive_defaults)
directives.update(self.compilation_directive_defaults)
directives.update(node.directive_comments)
self.directives = directives
node.directives = directives
self.visitchildren(node)
node.cython_module_names = self.cython_module_names
return node
# The following four functions track imports and cimports that
# begin with "cython"
def is_cython_directive(self, name):
return (name in Options.directive_types or
name in self.special_methods or
PyrexTypes.parse_basic_type(name))
def visit_CImportStatNode(self, node):
if node.module_name == u"cython":
self.cython_module_names.add(node.as_name or u"cython")
elif node.module_name.startswith(u"cython."):
if node.as_name:
self.directive_names[node.as_name] = node.module_name[7:]
else:
self.cython_module_names.add(u"cython")
# if this cimport was a compiler directive, we don't
# want to leave the cimport node sitting in the tree
return None
return node
def visit_FromCImportStatNode(self, node):
if (node.module_name == u"cython") or \
node.module_name.startswith(u"cython."):
submodule = (node.module_name + u".")[7:]
newimp = []
for pos, name, as_name, kind in node.imported_names:
full_name = submodule + name
if self.is_cython_directive(full_name):
if as_name is None:
as_name = full_name
self.directive_names[as_name] = full_name
if kind is not None:
self.context.nonfatal_error(PostParseError(pos,
"Compiler directive imports must be plain imports"))
else:
newimp.append((pos, name, as_name, kind))
if not newimp:
return None
node.imported_names = newimp
return node
def visit_FromImportStatNode(self, node):
if (node.module.module_name.value == u"cython") or \
node.module.module_name.value.startswith(u"cython."):
submodule = (node.module.module_name.value + u".")[7:]
newimp = []
for name, name_node in node.items:
full_name = submodule + name
if self.is_cython_directive(full_name):
self.directive_names[name_node.name] = full_name
else:
newimp.append((name, name_node))
if not newimp:
return None
node.items = newimp
return node
def visit_SingleAssignmentNode(self, node):
if (isinstance(node.rhs, ImportNode) and
node.rhs.module_name.value == u'cython'):
node = CImportStatNode(node.pos,
module_name = u'cython',
as_name = node.lhs.name)
self.visit_CImportStatNode(node)
else:
self.visitchildren(node)
return node
def visit_NameNode(self, node):
if node.name in self.cython_module_names:
node.is_cython_module = True
else:
node.cython_attribute = self.directive_names.get(node.name)
return node
def try_to_parse_directives(self, node):
# If node is the contents of an directive (in a with statement or
# decorator), returns a list of (directivename, value) pairs.
# Otherwise, returns None
if isinstance(node, CallNode):
self.visit(node.function)
optname = node.function.as_cython_attribute()
if optname:
directivetype = Options.directive_types.get(optname)
if directivetype:
args, kwds = node.explicit_args_kwds()
directives = []
key_value_pairs = []
if kwds is not None and directivetype is not dict:
for keyvalue in kwds.key_value_pairs:
key, value = keyvalue
sub_optname = "%s.%s" % (optname, key.value)
if Options.directive_types.get(sub_optname):
directives.append(self.try_to_parse_directive(sub_optname, [value], None, keyvalue.pos))
else:
key_value_pairs.append(keyvalue)
if not key_value_pairs:
kwds = None
else:
kwds.key_value_pairs = key_value_pairs
if directives and not kwds and not args:
return directives
directives.append(self.try_to_parse_directive(optname, args, kwds, node.function.pos))
return directives
return None
def try_to_parse_directive(self, optname, args, kwds, pos):
directivetype = Options.directive_types.get(optname)
if len(args) == 1 and isinstance(args[0], NoneNode):
return optname, Options.directive_defaults[optname]
elif directivetype is bool:
if kwds is not None or len(args) != 1 or not isinstance(args[0], BoolNode):
raise PostParseError(pos,
'The %s directive takes one compile-time boolean argument' % optname)
return (optname, args[0].value)
elif directivetype is str:
if kwds is not None or len(args) != 1 or not isinstance(args[0], (StringNode, UnicodeNode)):
raise PostParseError(pos,
'The %s directive takes one compile-time string argument' % optname)
return (optname, str(args[0].value))
elif directivetype is dict:
if len(args) != 0:
raise PostParseError(pos,
'The %s directive takes no prepositional arguments' % optname)
return optname, dict([(key.value, value) for key, value in kwds.key_value_pairs])
elif directivetype is list:
if kwds and len(kwds) != 0:
raise PostParseError(pos,
'The %s directive takes no keyword arguments' % optname)
return optname, [ str(arg.value) for arg in args ]
else:
assert False
def visit_with_directives(self, body, directives):
olddirectives = self.directives
newdirectives = copy.copy(olddirectives)
newdirectives.update(directives)
self.directives = newdirectives
assert isinstance(body, StatListNode), body
retbody = self.visit_Node(body)
directive = CompilerDirectivesNode(pos=retbody.pos, body=retbody,
directives=newdirectives)
self.directives = olddirectives
return directive
# Handle decorators
def visit_FuncDefNode(self, node):
directives = []
if node.decorators:
# Split the decorators into two lists -- real decorators and directives
realdecs = []
for dec in node.decorators:
new_directives = self.try_to_parse_directives(dec.decorator)
if new_directives is not None:
directives.extend(new_directives)
else:
realdecs.append(dec)
if realdecs and isinstance(node, CFuncDefNode):
raise PostParseError(realdecs[0].pos, "Cdef functions cannot take arbitrary decorators.")
else:
node.decorators = realdecs
if directives:
optdict = {}
directives.reverse() # Decorators coming first take precedence
for directive in directives:
name, value = directive
legal_scopes = Options.directive_scopes.get(name, None)
if not self.check_directive_scope(node.pos, name, 'function'):
continue
if name in optdict:
old_value = optdict[name]
# keywords and arg lists can be merged, everything
# else overrides completely
if isinstance(old_value, dict):
old_value.update(value)
elif isinstance(old_value, list):
old_value.extend(value)
else:
optdict[name] = value
else:
optdict[name] = value
body = StatListNode(node.pos, stats=[node])
return self.visit_with_directives(body, optdict)
else:
return self.visit_Node(node)
def visit_CVarDefNode(self, node):
if node.decorators:
for dec in node.decorators:
for directive in self.try_to_parse_directives(dec.decorator) or []:
if directive is not None and directive[0] == u'locals':
node.directive_locals = directive[1]
else:
self.context.nonfatal_error(PostParseError(dec.pos,
"Cdef functions can only take cython.locals() decorator."))
return node
# Handle with statements
def visit_WithStatNode(self, node):
directive_dict = {}
for directive in self.try_to_parse_directives(node.manager) or []:
if directive is not None:
if node.target is not None:
self.context.nonfatal_error(
PostParseError(node.pos, "Compiler directive with statements cannot contain 'as'"))
else:
name, value = directive
if self.check_directive_scope(node.pos, name, 'with statement'):
directive_dict[name] = value
if directive_dict:
return self.visit_with_directives(node.body, directive_dict)
return self.visit_Node(node)
class WithTransform(CythonTransform, SkipDeclarations):
# EXCINFO is manually set to a variable that contains
# the exc_info() tuple that can be generated by the enclosing except
# statement.
template_without_target = TreeFragment(u"""
MGR = EXPR
EXIT = MGR.__exit__
MGR.__enter__()
EXC = True
try:
try:
EXCINFO = None
BODY
except:
EXC = False
if not EXIT(*EXCINFO):
raise
finally:
if EXC:
EXIT(None, None, None)
""", temps=[u'MGR', u'EXC', u"EXIT"],
pipeline=[NormalizeTree(None)])
template_with_target = TreeFragment(u"""
MGR = EXPR
EXIT = MGR.__exit__
VALUE = MGR.__enter__()
EXC = True
try:
try:
EXCINFO = None
TARGET = VALUE
BODY
except:
EXC = False
if not EXIT(*EXCINFO):
raise
finally:
if EXC:
EXIT(None, None, None)
MGR = EXIT = VALUE = EXC = None
""", temps=[u'MGR', u'EXC', u"EXIT", u"VALUE"],
pipeline=[NormalizeTree(None)])
def visit_WithStatNode(self, node):
# TODO: Cleanup badly needed
TemplateTransform.temp_name_counter += 1
handle = "__tmpvar_%d" % TemplateTransform.temp_name_counter
self.visitchildren(node, ['body'])
excinfo_temp = NameNode(node.pos, name=handle)#TempHandle(Builtin.tuple_type)
if node.target is not None:
result = self.template_with_target.substitute({
u'EXPR' : node.manager,
u'BODY' : node.body,
u'TARGET' : node.target,
u'EXCINFO' : excinfo_temp
}, pos=node.pos)
else:
result = self.template_without_target.substitute({
u'EXPR' : node.manager,
u'BODY' : node.body,
u'EXCINFO' : excinfo_temp
}, pos=node.pos)
# Set except excinfo target to EXCINFO
try_except = result.stats[-1].body.stats[-1]
try_except.except_clauses[0].excinfo_target = NameNode(node.pos, name=handle)
# excinfo_temp.ref(node.pos))
# result.stats[-1].body.stats[-1] = TempsBlockNode(
# node.pos, temps=[excinfo_temp], body=try_except)
return result
def visit_ExprNode(self, node):
# With statements are never inside expressions.
return node
class DecoratorTransform(CythonTransform, SkipDeclarations):
def visit_DefNode(self, func_node):
self.visitchildren(func_node)
if not func_node.decorators:
return func_node
return self._handle_decorators(
func_node, func_node.name)
def _visit_CClassDefNode(self, class_node):
# This doesn't currently work, so it's disabled (also in the
# parser).
#
# Problem: assignments to cdef class names do not work. They
# would require an additional check anyway, as the extension
# type must not change its C type, so decorators cannot
# replace an extension type, just alter it and return it.
self.visitchildren(class_node)
if not class_node.decorators:
return class_node
return self._handle_decorators(
class_node, class_node.class_name)
def visit_ClassDefNode(self, class_node):
self.visitchildren(class_node)
if not class_node.decorators:
return class_node
return self._handle_decorators(
class_node, class_node.name)
def _handle_decorators(self, node, name):
decorator_result = NameNode(node.pos, name = name)
for decorator in node.decorators[::-1]:
decorator_result = SimpleCallNode(
decorator.pos,
function = decorator.decorator,
args = [decorator_result])
name_node = NameNode(node.pos, name = name)
reassignment = SingleAssignmentNode(
node.pos,
lhs = name_node,
rhs = decorator_result)
return [node, reassignment]
class AnalyseDeclarationsTransform(CythonTransform):
basic_property = TreeFragment(u"""
property NAME:
def __get__(self):
return ATTR
def __set__(self, value):
ATTR = value
""", level='c_class')
basic_pyobject_property = TreeFragment(u"""
property NAME:
def __get__(self):
return ATTR
def __set__(self, value):
ATTR = value
def __del__(self):
ATTR = None
""", level='c_class')
basic_property_ro = TreeFragment(u"""
property NAME:
def __get__(self):
return ATTR
""", level='c_class')
def __call__(self, root):
self.env_stack = [root.scope]
# needed to determine if a cdef var is declared after it's used.
self.seen_vars_stack = []
return super(AnalyseDeclarationsTransform, self).__call__(root)
def visit_NameNode(self, node):
self.seen_vars_stack[-1].add(node.name)
return node
def visit_ModuleNode(self, node):
self.seen_vars_stack.append(set())
node.analyse_declarations(self.env_stack[-1])
self.visitchildren(node)
self.seen_vars_stack.pop()
return node
def visit_LambdaNode(self, node):
node.analyse_declarations(self.env_stack[-1])
self.visitchildren(node)
return node
def visit_ClassDefNode(self, node):
self.env_stack.append(node.scope)
self.visitchildren(node)
self.env_stack.pop()
return node
def visit_FuncDefNode(self, node):
self.seen_vars_stack.append(set())
lenv = node.local_scope
node.body.analyse_control_flow(lenv) # this will be totally refactored
node.declare_arguments(lenv)
for var, type_node in node.directive_locals.items():
if not lenv.lookup_here(var): # don't redeclare args
type = type_node.analyse_as_type(lenv)
if type:
lenv.declare_var(var, type, type_node.pos)
else:
error(type_node.pos, "Not a type")
node.body.analyse_declarations(lenv)
self.env_stack.append(lenv)
self.visitchildren(node)
self.env_stack.pop()
self.seen_vars_stack.pop()
return node
def visit_ComprehensionNode(self, node):
self.visitchildren(node)
node.analyse_declarations(self.env_stack[-1])
return node
def visit_ScopedExprNode(self, node):
node.analyse_declarations(self.env_stack[-1])
if self.seen_vars_stack:
self.seen_vars_stack.append(set(self.seen_vars_stack[-1]))
else:
self.seen_vars_stack.append(set())
self.env_stack.append(node.expr_scope)
self.visitchildren(node)
self.env_stack.pop()
self.seen_vars_stack.pop()
return node
def visit_TempResultFromStatNode(self, node):
self.visitchildren(node)
node.analyse_declarations(self.env_stack[-1])
return node
# Some nodes are no longer needed after declaration
# analysis and can be dropped. The analysis was performed
# on these nodes in a seperate recursive process from the
# enclosing function or module, so we can simply drop them.
def visit_CDeclaratorNode(self, node):
# necessary to ensure that all CNameDeclaratorNodes are visited.
self.visitchildren(node)
return node
def visit_CTypeDefNode(self, node):
return node
def visit_CBaseTypeNode(self, node):
return None
def visit_CEnumDefNode(self, node):
if node.visibility == 'public':
return node
else:
return None
def visit_CStructOrUnionDefNode(self, node):
return None
def visit_CNameDeclaratorNode(self, node):
if node.name in self.seen_vars_stack[-1]:
entry = self.env_stack[-1].lookup(node.name)
if entry is None or entry.visibility != 'extern':
warning(node.pos, "cdef variable '%s' declared after it is used" % node.name, 2)
self.visitchildren(node)
return node
def visit_CVarDefNode(self, node):
# to ensure all CNameDeclaratorNodes are visited.
self.visitchildren(node)
if node.properties:
stats = []
for entry in node.properties:
property = self.create_Property(entry)
property.analyse_declarations(node.dest_scope)
self.visit(property)
stats.append(property)
return StatListNode(pos=node.pos, stats=stats)
else:
return None
def create_Property(self, entry):
if entry.visibility == 'public':
if entry.type.is_pyobject:
template = self.basic_pyobject_property
else:
template = self.basic_property
elif entry.visibility == 'readonly':
template = self.basic_property_ro
property = template.substitute({
u"ATTR": AttributeNode(pos=entry.pos,
obj=NameNode(pos=entry.pos, name="self"),
attribute=entry.name),
}, pos=entry.pos).stats[0]
property.name = entry.name
# ---------------------------------------
# XXX This should go to AutoDocTransforms
# ---------------------------------------
if (Options.docstrings and
self.current_directives['embedsignature']):
attr_name = entry.name
type_name = entry.type.declaration_code("", for_display=1)
default_value = ''
if not entry.type.is_pyobject:
type_name = "'%s'" % type_name
elif entry.type.is_extension_type:
type_name = entry.type.module_name + '.' + type_name
if entry.init is not None:
default_value = ' = ' + entry.init
elif entry.init_to_none:
default_value = ' = ' + repr(None)
docstring = attr_name + ': ' + type_name + default_value
property.doc = EncodedString(docstring)
# ---------------------------------------
return property
class AnalyseExpressionsTransform(CythonTransform):
def visit_ModuleNode(self, node):
node.scope.infer_types()
node.body.analyse_expressions(node.scope)
self.visitchildren(node)
return node
def visit_FuncDefNode(self, node):
node.local_scope.infer_types()
node.body.analyse_expressions(node.local_scope)
self.visitchildren(node)
return node
def visit_ScopedExprNode(self, node):
if node.expr_scope is not None:
node.expr_scope.infer_types()
node.analyse_scoped_expressions(node.expr_scope)
self.visitchildren(node)
return node
class AlignFunctionDefinitions(CythonTransform):
"""
This class takes the signatures from a .pxd file and applies them to
the def methods in a .py file.
"""
def visit_ModuleNode(self, node):
self.scope = node.scope
self.directives = node.directives
self.visitchildren(node)
return node
def visit_PyClassDefNode(self, node):
pxd_def = self.scope.lookup(node.name)
if pxd_def:
if pxd_def.is_cclass:
return self.visit_CClassDefNode(node.as_cclass(), pxd_def)
else:
error(node.pos, "'%s' redeclared" % node.name)
error(pxd_def.pos, "previous declaration here")
return None
else:
return node
def visit_CClassDefNode(self, node, pxd_def=None):
if pxd_def is None:
pxd_def = self.scope.lookup(node.class_name)
if pxd_def:
outer_scope = self.scope
self.scope = pxd_def.type.scope
self.visitchildren(node)
if pxd_def:
self.scope = outer_scope
return node
def visit_DefNode(self, node):
pxd_def = self.scope.lookup(node.name)
if pxd_def:
if self.scope.is_c_class_scope and len(pxd_def.type.args) > 0:
# The self parameter type needs adjusting.
pxd_def.type.args[0].type = self.scope.parent_type
if pxd_def.is_cfunction:
node = node.as_cfunction(pxd_def)
else:
error(node.pos, "'%s' redeclared" % node.name)
error(pxd_def.pos, "previous declaration here")
return None
elif self.scope.is_module_scope and self.directives['auto_cpdef']:
node = node.as_cfunction(scope=self.scope)
# Enable this when internal def functions are allowed.
# self.visitchildren(node)
return node
class MarkClosureVisitor(CythonTransform):
needs_closure = False
def visit_FuncDefNode(self, node):
self.needs_closure = False
self.visitchildren(node)
node.needs_closure = self.needs_closure
self.needs_closure = True
return node
def visit_CFuncDefNode(self, node):
self.visit_FuncDefNode(node)
if node.needs_closure:
error(node.pos, "closures inside cdef functions not yet supported")
return node
def visit_LambdaNode(self, node):
self.needs_closure = False
self.visitchildren(node)
node.needs_closure = self.needs_closure
self.needs_closure = True
return node
def visit_ClassDefNode(self, node):
self.visitchildren(node)
self.needs_closure = True
return node
class CreateClosureClasses(CythonTransform):
# Output closure classes in module scope for all functions
# that need it.
def visit_ModuleNode(self, node):
self.module_scope = node.scope
self.visitchildren(node)
return node
def create_class_from_scope(self, node, target_module_scope):
as_name = "%s%s" % (Naming.closure_class_prefix, node.entry.cname)
func_scope = node.local_scope
entry = target_module_scope.declare_c_class(name = as_name,
pos = node.pos, defining = True, implementing = True)
func_scope.scope_class = entry
class_scope = entry.type.scope
class_scope.is_internal = True
if node.entry.scope.is_closure_scope:
class_scope.declare_var(pos=node.pos,
name=Naming.outer_scope_cname, # this could conflict?
cname=Naming.outer_scope_cname,
type=node.entry.scope.scope_class.type,
is_cdef=True)
entries = func_scope.entries.items()
entries.sort()
for name, entry in entries:
# This is wasteful--we should do this later when we know
# which vars are actually being used inside...
#
# Also, this happens before type inference and type
# analysis, so the entries created here may end up having
# incorrect or at least unspecified types.
class_scope.declare_var(pos=entry.pos,
name=entry.name,
cname=entry.cname,
type=entry.type,
is_cdef=True)
def visit_FuncDefNode(self, node):
if node.needs_closure:
self.create_class_from_scope(node, self.module_scope)
self.visitchildren(node)
return node
class GilCheck(VisitorTransform):
"""
Call `node.gil_check(env)` on each node to make sure we hold the
GIL when we need it. Raise an error when on Python operations
inside a `nogil` environment.
"""
def __call__(self, root):
self.env_stack = [root.scope]
self.nogil = False
return super(GilCheck, self).__call__(root)
def visit_FuncDefNode(self, node):
self.env_stack.append(node.local_scope)
was_nogil = self.nogil
self.nogil = node.local_scope.nogil
if self.nogil and node.nogil_check:
node.nogil_check(node.local_scope)
self.visitchildren(node)
self.env_stack.pop()
self.nogil = was_nogil
return node
def visit_GILStatNode(self, node):
env = self.env_stack[-1]
if self.nogil and node.nogil_check: node.nogil_check()
was_nogil = self.nogil
self.nogil = (node.state == 'nogil')
self.visitchildren(node)
self.nogil = was_nogil
return node
def visit_Node(self, node):
if self.env_stack and self.nogil and node.nogil_check:
node.nogil_check(self.env_stack[-1])
self.visitchildren(node)
return node
class TransformBuiltinMethods(EnvTransform):
def visit_SingleAssignmentNode(self, node):
if node.declaration_only:
return None
else:
self.visitchildren(node)
return node
def visit_AttributeNode(self, node):
self.visitchildren(node)
return self.visit_cython_attribute(node)
def visit_NameNode(self, node):
return self.visit_cython_attribute(node)
def visit_cython_attribute(self, node):
attribute = node.as_cython_attribute()
if attribute:
if attribute == u'compiled':
node = BoolNode(node.pos, value=True)
elif attribute == u'NULL':
node = NullNode(node.pos)
elif attribute in (u'set', u'frozenset'):
node = NameNode(node.pos, name=EncodedString(attribute),
entry=self.current_env().builtin_scope().lookup_here(attribute))
elif not PyrexTypes.parse_basic_type(attribute):
error(node.pos, u"'%s' not a valid cython attribute or is being used incorrectly" % attribute)
return node
def visit_SimpleCallNode(self, node):
# locals builtin
if isinstance(node.function, ExprNodes.NameNode):
if node.function.name == 'locals':
lenv = self.current_env()
entry = lenv.lookup_here('locals')
if entry:
# not the builtin 'locals'
return node
if len(node.args) > 0:
error(self.pos, "Builtin 'locals()' called with wrong number of args, expected 0, got %d" % len(node.args))
return node
pos = node.pos
items = [ExprNodes.DictItemNode(pos,
key=ExprNodes.StringNode(pos, value=var),
value=ExprNodes.NameNode(pos, name=var)) for var in lenv.entries]
return ExprNodes.DictNode(pos, key_value_pairs=items)
# cython.foo
function = node.function.as_cython_attribute()
if function:
if function in InterpretCompilerDirectives.unop_method_nodes:
if len(node.args) != 1:
error(node.function.pos, u"%s() takes exactly one argument" % function)
else:
node = InterpretCompilerDirectives.unop_method_nodes[function](node.function.pos, operand=node.args[0])
elif function in InterpretCompilerDirectives.binop_method_nodes:
if len(node.args) != 2:
error(node.function.pos, u"%s() takes exactly two arguments" % function)
else:
node = InterpretCompilerDirectives.binop_method_nodes[function](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")
else:
type = node.args[0].analyse_as_type(self.current_env())
if type:
node = TypecastNode(node.function.pos, type=type, operand=node.args[1])
else:
error(node.args[0].pos, "Not a type")
elif function == u'sizeof':
if len(node.args) != 1:
error(node.function.pos, u"sizeof() takes exactly one argument")
else:
type = node.args[0].analyse_as_type(self.current_env())
if type:
node = SizeofTypeNode(node.function.pos, arg_type=type)
else:
node = SizeofVarNode(node.function.pos, operand=node.args[0])
elif function == 'cmod':
if len(node.args) != 2:
error(node.function.pos, u"cmod() takes exactly two arguments")
else:
node = binop_node(node.function.pos, '%', node.args[0], node.args[1])
node.cdivision = True
elif function == 'cdiv':
if len(node.args) != 2:
error(node.function.pos, u"cdiv() takes exactly two arguments")
else:
node = binop_node(node.function.pos, '/', node.args[0], node.args[1])
node.cdivision = True
elif function == u'set':
node.function = NameNode(node.pos, name=EncodedString('set'))
else:
error(node.function.pos, u"'%s' not a valid cython language construct" % function)
self.visitchildren(node)
return node
def _create_xmlnode(tb, name, attrs=None):
"create a xml node with name name and attrs attrs given TreeBuilder tb"
tb.start(name, attrs or {})
tb.end(name)
class DebuggerTransform(CythonTransform):
"""
Class to output debugging information for cygdb
It writes debug information to cython_debug/cython_debug_info_
in the build directory. Also sets all functions' visibility to extern to
enable debugging
"""
def __init__(self, context):
super(DebuggerTransform, self).__init__(context)
if etree is None:
raise Errors.NoElementTreeInstalledException()
else:
self.tb = etree.TreeBuilder()
self.visited = set()
def visit_ModuleNode(self, node):
self.module_name = node.full_module_name
attrs = dict(
module_name=self.module_name,
filename=node.pos[0].filename)
self.tb.start('Module', attrs)
# serialize functions
self.tb.start('Functions', {})
self.visitchildren(node)
self.tb.end('Functions')
# 2.3 compatibility. Serialize global variables
self.tb.start('Globals', {})
entries = {}
for k, v in node.scope.entries.iteritems():
if (v.qualified_name not in self.visited and
not v.name.startswith('__pyx_')):
# if v.qualified_name == 'testcython.G': import pdb; pdb.set_trace()
entries[k]= v
self.serialize_local_variables(entries)
self.tb.end('Globals')
self.tb.end('Module')
return node
def visit_FuncDefNode(self, node):
self.visited.add(node.local_scope.qualified_name)
node.entry.visibility = 'extern'
if node.py_func is None:
pf_cname = ''
else:
pf_cname = node.py_func.entry.func_cname
attrs = dict(
name=node.entry.name,
cname=node.entry.func_cname,
pf_cname=pf_cname,
qualified_name=node.local_scope.qualified_name,
lineno=str(node.pos[1]))
self.tb.start('Function', attrs=attrs)
self.tb.start('Locals', {})
self.serialize_local_variables(node.local_scope.entries)
self.tb.end('Locals')
self.tb.start('Arguments', {})
for arg in node.local_scope.arg_entries:
_create_xmlnode(self.tb, arg.name)
self.tb.end('Arguments')
self.tb.end('Function')
return node
def serialize_local_variables(self, entries):
for entry in entries.values():
if entry.type.is_pyobject:
vartype = 'PyObject'
else:
vartype = 'CObject'
cname = entry.cname
if entry.type.is_extension_type:
cname = entry.type.typeptr_cname
attrs = dict(
name=entry.name,
cname=cname,
qualified_name=entry.qualified_name,
type=vartype)
_create_xmlnode(self.tb, 'LocalVar', attrs)
def __call__(self, root):
self.tb.start('cython_debug', attrs=dict(version='1.0'))
super(DebuggerTransform, self).__call__(root)
self.tb.end('cython_debug')
xml_root_element = self.tb.close()
try:
os.mkdir('cython_debug')
except OSError, e:
if e.errno != errno.EEXIST:
raise
et = etree.ElementTree(xml_root_element)
kw = {}
if have_lxml:
kw['pretty_print'] = True
et.write("cython_debug/cython_debug_info_" + self.module_name,
encoding="UTF-8",
**kw)
return root cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Parsing.pxd 0000664 0000000 0000000 00000016032 11446142532 0025104 0 ustar 00root root 0000000 0000000 # We declare all of these here to type the first argument.
from Cython.Compiler.Scanning cimport PyrexScanner
cpdef p_ident(PyrexScanner s, message =*)
cpdef p_ident_list(PyrexScanner s)
cpdef p_binop_operator(PyrexScanner s)
cpdef p_binop_expr(PyrexScanner s, ops, p_sub_expr)
cpdef p_lambdef(PyrexScanner s, bint allow_conditional=*)
cpdef p_lambdef_nocond(PyrexScanner s)
cpdef p_test(PyrexScanner s)
cpdef p_test_nocond(PyrexScanner s)
cpdef p_or_test(PyrexScanner s)
cpdef p_rassoc_binop_expr(PyrexScanner s, ops, p_subexpr)
cpdef p_and_test(PyrexScanner s)
cpdef p_not_test(PyrexScanner s)
cpdef p_comparison(PyrexScanner s)
cpdef p_test_or_starred_expr(PyrexScanner s)
cpdef p_starred_expr(PyrexScanner s)
cpdef p_cascaded_cmp(PyrexScanner s)
cpdef p_cmp_op(PyrexScanner s)
cpdef p_bit_expr(PyrexScanner s)
cpdef p_xor_expr(PyrexScanner s)
cpdef p_and_expr(PyrexScanner s)
cpdef p_shift_expr(PyrexScanner s)
cpdef p_arith_expr(PyrexScanner s)
cpdef p_term(PyrexScanner s)
cpdef p_factor(PyrexScanner s)
cpdef p_typecast(PyrexScanner s)
cpdef p_sizeof(PyrexScanner s)
cpdef p_yield_expression(PyrexScanner s)
cpdef p_yield_statement(PyrexScanner s)
cpdef p_power(PyrexScanner s)
cpdef p_new_expr(PyrexScanner s)
cpdef p_trailer(PyrexScanner s, node1)
cpdef p_call(PyrexScanner s, function)
cpdef p_index(PyrexScanner s, base)
cpdef p_subscript_list(PyrexScanner s)
cpdef p_subscript(PyrexScanner s)
cpdef p_slice_element(PyrexScanner s, follow_set)
cpdef expect_ellipsis(PyrexScanner s)
cpdef make_slice_nodes(pos, subscripts)
cpdef make_slice_node(pos, start, stop = *, step = *)
cpdef p_atom(PyrexScanner s)
cpdef p_name(PyrexScanner s, name)
cpdef p_cat_string_literal(PyrexScanner s)
cpdef p_opt_string_literal(PyrexScanner s, required_type=*)
cpdef bint check_for_non_ascii_characters(unicode string)
cpdef p_string_literal(PyrexScanner s, kind_override=*)
cpdef p_list_maker(PyrexScanner s)
cpdef p_comp_iter(PyrexScanner s, body)
cpdef p_comp_for(PyrexScanner s, body)
cpdef p_comp_if(PyrexScanner s, body)
cpdef p_dict_or_set_maker(PyrexScanner s)
cpdef p_backquote_expr(PyrexScanner s)
cpdef p_simple_expr_list(PyrexScanner s, expr=*)
cpdef p_test_or_starred_expr_list(s, expr=*)
cpdef p_testlist(PyrexScanner s)
cpdef p_testlist_star_expr(PyrexScanner s)
cpdef p_testlist_comp(PyrexScanner s)
cpdef p_genexp(PyrexScanner s, expr)
#-------------------------------------------------------
#
# Statements
#
#-------------------------------------------------------
cpdef p_global_statement(PyrexScanner s)
cpdef p_expression_or_assignment(PyrexScanner s)
cpdef p_print_statement(PyrexScanner s)
cpdef p_exec_statement(PyrexScanner s)
cpdef p_del_statement(PyrexScanner s)
cpdef p_pass_statement(PyrexScanner s, bint with_newline = *)
cpdef p_break_statement(PyrexScanner s)
cpdef p_continue_statement(PyrexScanner s)
cpdef p_return_statement(PyrexScanner s)
cpdef p_raise_statement(PyrexScanner s)
cpdef p_import_statement(PyrexScanner s)
cpdef p_from_import_statement(PyrexScanner s, bint first_statement = *)
cpdef p_imported_name(PyrexScanner s, bint is_cimport)
cpdef p_dotted_name(PyrexScanner s, bint as_allowed)
cpdef p_as_name(PyrexScanner s)
cpdef p_assert_statement(PyrexScanner s)
cpdef p_if_statement(PyrexScanner s)
cpdef p_if_clause(PyrexScanner s)
cpdef p_else_clause(PyrexScanner s)
cpdef p_while_statement(PyrexScanner s)
cpdef p_for_statement(PyrexScanner s)
cpdef p_for_bounds(PyrexScanner s, bint allow_testlist = *)
cpdef p_for_from_relation(PyrexScanner s)
cpdef p_for_from_step(PyrexScanner s)
cpdef p_target(PyrexScanner s, terminator)
cpdef p_for_target(PyrexScanner s)
cpdef p_for_iterator(PyrexScanner s, bint allow_testlist = *)
cpdef p_try_statement(PyrexScanner s)
cpdef p_except_clause(PyrexScanner s)
cpdef p_include_statement(PyrexScanner s, ctx)
cpdef p_with_statement(PyrexScanner s)
cpdef p_simple_statement(PyrexScanner s, bint first_statement = *)
cpdef p_simple_statement_list(PyrexScanner s, ctx, bint first_statement = *)
cpdef p_compile_time_expr(PyrexScanner s)
cpdef p_DEF_statement(PyrexScanner s)
cpdef p_IF_statement(PyrexScanner s, ctx)
cpdef p_statement(PyrexScanner s, ctx, bint first_statement = *)
cpdef p_statement_list(PyrexScanner s, ctx, bint first_statement = *)
cpdef p_suite(PyrexScanner s, ctx = *, bint with_doc = *, bint with_pseudo_doc = *)
cpdef p_positional_and_keyword_args(PyrexScanner s, end_sy_set, templates = *)
cpdef p_c_base_type(PyrexScanner s, bint self_flag = *, bint nonempty = *, templates = *)
cpdef p_calling_convention(PyrexScanner s)
cpdef p_c_complex_base_type(PyrexScanner s)
cpdef p_c_simple_base_type(PyrexScanner s, bint self_flag, bint nonempty, templates = *)
cpdef p_buffer_or_template(PyrexScanner s, base_type_node, templates)
cpdef bint looking_at_name(PyrexScanner s) except -2
cpdef bint looking_at_expr(PyrexScanner s) except -2
cpdef bint looking_at_base_type(PyrexScanner s) except -2
cpdef bint looking_at_dotted_name(PyrexScanner s) except -2
cpdef p_sign_and_longness(PyrexScanner s)
cpdef p_opt_cname(PyrexScanner s)
cpdef p_c_declarator(PyrexScanner s, ctx = *, bint empty = *, bint is_type = *, bint cmethod_flag = *,
bint assignable = *, bint nonempty = *,
bint calling_convention_allowed = *)
cpdef p_c_array_declarator(PyrexScanner s, base)
cpdef p_c_func_declarator(PyrexScanner s, pos, ctx, base, bint cmethod_flag)
cpdef p_c_simple_declarator(PyrexScanner s, ctx, bint empty, bint is_type, bint cmethod_flag,
bint assignable, bint nonempty)
cpdef p_nogil(PyrexScanner s)
cpdef p_with_gil(PyrexScanner s)
cpdef p_exception_value_clause(PyrexScanner s)
cpdef p_c_arg_list(PyrexScanner s, ctx = *, bint in_pyfunc = *, bint cmethod_flag = *,
bint nonempty_declarators = *, bint kw_only = *, bint annotated = *)
cpdef p_optional_ellipsis(PyrexScanner s)
cpdef p_c_arg_decl(PyrexScanner s, ctx, in_pyfunc, bint cmethod_flag = *, bint nonempty = *, bint kw_only = *, bint annotated = *)
cpdef p_api(PyrexScanner s)
cpdef p_cdef_statement(PyrexScanner s, ctx)
cpdef p_cdef_block(PyrexScanner s, ctx)
cpdef p_cdef_extern_block(PyrexScanner s, pos, ctx)
cpdef p_c_enum_definition(PyrexScanner s, pos, ctx)
cpdef p_c_enum_line(PyrexScanner s, ctx, list items)
cpdef p_c_enum_item(PyrexScanner s, ctx, list items)
cpdef p_c_struct_or_union_definition(PyrexScanner s, pos, ctx)
cpdef p_visibility(PyrexScanner s, prev_visibility)
cpdef p_c_modifiers(PyrexScanner s)
cpdef p_c_func_or_var_declaration(PyrexScanner s, pos, ctx)
cpdef p_ctypedef_statement(PyrexScanner s, ctx)
cpdef p_decorators(PyrexScanner s)
cpdef p_def_statement(PyrexScanner s, list decorators = *)
cpdef p_varargslist(PyrexScanner s, terminator=*, bint annotated = *)
cpdef p_py_arg_decl(PyrexScanner s)
cpdef p_class_statement(PyrexScanner s, decorators)
cpdef p_c_class_definition(PyrexScanner s, pos, ctx)
cpdef p_c_class_options(PyrexScanner s)
cpdef p_property_decl(PyrexScanner s)
cpdef p_doc_string(PyrexScanner s)
cpdef p_code(PyrexScanner s, level= *)
cpdef p_compiler_directive_comments(PyrexScanner s)
cpdef p_module(PyrexScanner s, pxd, full_module_name)
cpdef p_cpp_class_definition(PyrexScanner s, pos, ctx)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Parsing.py 0000664 0000000 0000000 00000266200 11446142532 0024745 0 ustar 00root root 0000000 0000000 # cython: auto_cpdef=True, infer_types=True
#
# Pyrex Parser
#
# This should be done automatically
import cython
cython.declare(Nodes=object, ExprNodes=object, EncodedString=object)
import os
import re
import sys
from Cython.Compiler.Scanning import PyrexScanner, FileSourceDescriptor
import Nodes
import ExprNodes
import StringEncoding
from StringEncoding import EncodedString, BytesLiteral, _unicode, _bytes
from ModuleNode import ModuleNode
from Errors import error, warning, InternalError
from Cython import Utils
import Future
import Options
class Ctx(object):
# Parsing context
level = 'other'
visibility = 'private'
cdef_flag = 0
typedef_flag = 0
api = 0
overridable = 0
nogil = 0
namespace = None
templates = None
def __init__(self, **kwds):
self.__dict__.update(kwds)
def __call__(self, **kwds):
ctx = Ctx()
d = ctx.__dict__
d.update(self.__dict__)
d.update(kwds)
return ctx
def p_ident(s, message = "Expected an identifier"):
if s.sy == 'IDENT':
name = s.systring
s.next()
return name
else:
s.error(message)
def p_ident_list(s):
names = []
while s.sy == 'IDENT':
names.append(s.systring)
s.next()
if s.sy != ',':
break
s.next()
return names
#------------------------------------------
#
# Expressions
#
#------------------------------------------
def p_binop_operator(s):
pos = s.position()
op = s.sy
s.next()
return op, pos
def p_binop_expr(s, ops, p_sub_expr):
n1 = p_sub_expr(s)
while s.sy in ops:
op, pos = p_binop_operator(s)
n2 = p_sub_expr(s)
n1 = ExprNodes.binop_node(pos, op, n1, n2)
if op == '/':
if Future.division in s.context.future_directives:
n1.truedivision = True
else:
n1.truedivision = None # unknown
return n1
#lambdef: 'lambda' [varargslist] ':' test
def p_lambdef(s, allow_conditional=True):
# s.sy == 'lambda'
pos = s.position()
s.next()
if s.sy == ':':
args = []
star_arg = starstar_arg = None
else:
args, star_arg, starstar_arg = p_varargslist(
s, terminator=':', annotated=False)
s.expect(':')
if allow_conditional:
expr = p_test(s)
else:
expr = p_test_nocond(s)
return ExprNodes.LambdaNode(
pos, args = args,
star_arg = star_arg, starstar_arg = starstar_arg,
result_expr = expr)
#lambdef_nocond: 'lambda' [varargslist] ':' test_nocond
def p_lambdef_nocond(s):
return p_lambdef(s, allow_conditional=False)
#test: or_test ['if' or_test 'else' test] | lambdef
def p_test(s):
if s.sy == 'lambda':
return p_lambdef(s)
pos = s.position()
expr = p_or_test(s)
if s.sy == 'if':
s.next()
test = p_or_test(s)
s.expect('else')
other = p_test(s)
return ExprNodes.CondExprNode(pos, test=test, true_val=expr, false_val=other)
else:
return expr
#test_nocond: or_test | lambdef_nocond
def p_test_nocond(s):
if s.sy == 'lambda':
return p_lambdef_nocond(s)
else:
return p_or_test(s)
#or_test: and_test ('or' and_test)*
def p_or_test(s):
return p_rassoc_binop_expr(s, ('or',), p_and_test)
def p_rassoc_binop_expr(s, ops, p_subexpr):
n1 = p_subexpr(s)
if s.sy in ops:
pos = s.position()
op = s.sy
s.next()
n2 = p_rassoc_binop_expr(s, ops, p_subexpr)
n1 = ExprNodes.binop_node(pos, op, n1, n2)
return n1
#and_test: not_test ('and' not_test)*
def p_and_test(s):
#return p_binop_expr(s, ('and',), p_not_test)
return p_rassoc_binop_expr(s, ('and',), p_not_test)
#not_test: 'not' not_test | comparison
def p_not_test(s):
if s.sy == 'not':
pos = s.position()
s.next()
return ExprNodes.NotNode(pos, operand = p_not_test(s))
else:
return p_comparison(s)
#comparison: expr (comp_op expr)*
#comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not'
def p_comparison(s):
n1 = p_starred_expr(s)
if s.sy in comparison_ops:
pos = s.position()
op = p_cmp_op(s)
n2 = p_starred_expr(s)
n1 = ExprNodes.PrimaryCmpNode(pos,
operator = op, operand1 = n1, operand2 = n2)
if s.sy in comparison_ops:
n1.cascade = p_cascaded_cmp(s)
return n1
def p_test_or_starred_expr(s):
if s.sy == '*':
return p_starred_expr(s)
else:
return p_test(s)
def p_starred_expr(s):
pos = s.position()
if s.sy == '*':
starred = True
s.next()
else:
starred = False
expr = p_bit_expr(s)
if starred:
expr = ExprNodes.StarredTargetNode(pos, expr)
return expr
def p_cascaded_cmp(s):
pos = s.position()
op = p_cmp_op(s)
n2 = p_starred_expr(s)
result = ExprNodes.CascadedCmpNode(pos,
operator = op, operand2 = n2)
if s.sy in comparison_ops:
result.cascade = p_cascaded_cmp(s)
return result
def p_cmp_op(s):
if s.sy == 'not':
s.next()
s.expect('in')
op = 'not_in'
elif s.sy == 'is':
s.next()
if s.sy == 'not':
s.next()
op = 'is_not'
else:
op = 'is'
else:
op = s.sy
s.next()
if op == '<>':
op = '!='
return op
comparison_ops = (
'<', '>', '==', '>=', '<=', '<>', '!=',
'in', 'is', 'not'
)
#expr: xor_expr ('|' xor_expr)*
def p_bit_expr(s):
return p_binop_expr(s, ('|',), p_xor_expr)
#xor_expr: and_expr ('^' and_expr)*
def p_xor_expr(s):
return p_binop_expr(s, ('^',), p_and_expr)
#and_expr: shift_expr ('&' shift_expr)*
def p_and_expr(s):
return p_binop_expr(s, ('&',), p_shift_expr)
#shift_expr: arith_expr (('<<'|'>>') arith_expr)*
def p_shift_expr(s):
return p_binop_expr(s, ('<<', '>>'), p_arith_expr)
#arith_expr: term (('+'|'-') term)*
def p_arith_expr(s):
return p_binop_expr(s, ('+', '-'), p_term)
#term: factor (('*'|'/'|'%') factor)*
def p_term(s):
return p_binop_expr(s, ('*', '/', '%', '//'), p_factor)
#factor: ('+'|'-'|'~'|'&'|typecast|sizeof) factor | power
def p_factor(s):
sy = s.sy
if sy in ('+', '-', '~'):
op = s.sy
pos = s.position()
s.next()
return ExprNodes.unop_node(pos, op, p_factor(s))
elif sy == '&':
pos = s.position()
s.next()
arg = p_factor(s)
return ExprNodes.AmpersandNode(pos, operand = arg)
elif sy == "<":
return p_typecast(s)
elif sy == 'IDENT' and s.systring == "sizeof":
return p_sizeof(s)
else:
return p_power(s)
def p_typecast(s):
# s.sy == "<"
pos = s.position()
s.next()
base_type = p_c_base_type(s)
if base_type.name is None:
s.error("Unknown type")
declarator = p_c_declarator(s, empty = 1)
if s.sy == '?':
s.next()
typecheck = 1
else:
typecheck = 0
s.expect(">")
operand = p_factor(s)
return ExprNodes.TypecastNode(pos,
base_type = base_type,
declarator = declarator,
operand = operand,
typecheck = typecheck)
def p_sizeof(s):
# s.sy == ident "sizeof"
pos = s.position()
s.next()
s.expect('(')
# Here we decide if we are looking at an expression or type
# If it is actually a type, but parsable as an expression,
# we treat it as an expression here.
if looking_at_expr(s):
operand = p_test(s)
node = ExprNodes.SizeofVarNode(pos, operand = operand)
else:
base_type = p_c_base_type(s)
declarator = p_c_declarator(s, empty = 1)
node = ExprNodes.SizeofTypeNode(pos,
base_type = base_type, declarator = declarator)
s.expect(')')
return node
def p_yield_expression(s):
# s.sy == "yield"
pos = s.position()
s.next()
if s.sy != ')' and s.sy not in statement_terminators:
arg = p_testlist(s)
else:
arg = None
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)
#power: atom trailer* ('**' factor)*
def p_power(s):
if s.systring == 'new' and s.peek()[0] == 'IDENT':
return p_new_expr(s)
n1 = p_atom(s)
while s.sy in ('(', '[', '.'):
n1 = p_trailer(s, n1)
if s.sy == '**':
pos = s.position()
s.next()
n2 = p_factor(s)
n1 = ExprNodes.binop_node(pos, '**', n1, n2)
return n1
def p_new_expr(s):
# s.systring == 'new'.
pos = s.position()
s.next()
cppclass = p_c_base_type(s)
return p_call(s, ExprNodes.NewExprNode(pos, cppclass = cppclass))
#trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
def p_trailer(s, node1):
pos = s.position()
if s.sy == '(':
return p_call(s, node1)
elif s.sy == '[':
return p_index(s, node1)
else: # s.sy == '.'
s.next()
name = EncodedString( p_ident(s) )
return ExprNodes.AttributeNode(pos,
obj = node1, attribute = name)
# arglist: argument (',' argument)* [',']
# argument: [test '='] test # Really [keyword '='] test
def p_call(s, function):
# s.sy == '('
pos = s.position()
s.next()
positional_args = []
keyword_args = []
star_arg = None
starstar_arg = None
while s.sy not in ('**', ')'):
if s.sy == '*':
if star_arg:
s.error("only one star-arg parameter allowed",
pos = s.position())
s.next()
star_arg = p_test(s)
else:
arg = p_test(s)
if s.sy == '=':
s.next()
if not arg.is_name:
s.error("Expected an identifier before '='",
pos = arg.pos)
encoded_name = EncodedString(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 star_arg:
s.error("Non-keyword arg following star-arg",
pos = arg.pos)
positional_args.append(arg)
if s.sy != ',':
break
s.next()
if s.sy == 'for':
if len(positional_args) == 1 and not star_arg:
positional_args = [ p_genexp(s, positional_args[0]) ]
elif s.sy == '**':
s.next()
starstar_arg = p_test(s)
if s.sy == ',':
s.next()
s.expect(')')
if not (keyword_args or star_arg or starstar_arg):
return ExprNodes.SimpleCallNode(pos,
function = function,
args = positional_args)
else:
arg_tuple = None
keyword_dict = None
if positional_args or not star_arg:
arg_tuple = ExprNodes.TupleNode(pos,
args = positional_args)
if star_arg:
star_arg_tuple = ExprNodes.AsTupleNode(pos, arg = star_arg)
if arg_tuple:
arg_tuple = ExprNodes.binop_node(pos,
operator = '+', operand1 = arg_tuple,
operand2 = star_arg_tuple)
else:
arg_tuple = star_arg_tuple
if keyword_args:
keyword_args = [ExprNodes.DictItemNode(pos=key.pos, key=key, value=value)
for key, value in keyword_args]
keyword_dict = ExprNodes.DictNode(pos,
key_value_pairs = keyword_args)
return ExprNodes.GeneralCallNode(pos,
function = function,
positional_args = arg_tuple,
keyword_args = keyword_dict,
starstar_arg = starstar_arg)
#lambdef: 'lambda' [varargslist] ':' test
#subscriptlist: subscript (',' subscript)* [',']
def p_index(s, base):
# s.sy == '['
pos = s.position()
s.next()
subscripts = p_subscript_list(s)
if len(subscripts) == 1 and len(subscripts[0]) == 2:
start, stop = subscripts[0]
result = ExprNodes.SliceIndexNode(pos,
base = base, start = start, stop = stop)
else:
indexes = make_slice_nodes(pos, subscripts)
if len(indexes) == 1:
index = indexes[0]
else:
index = ExprNodes.TupleNode(pos, args = indexes)
result = ExprNodes.IndexNode(pos,
base = base, index = index)
s.expect(']')
return result
def p_subscript_list(s):
items = [p_subscript(s)]
while s.sy == ',':
s.next()
if s.sy == ']':
break
items.append(p_subscript(s))
return items
#subscript: '.' '.' '.' | test | [test] ':' [test] [':' [test]]
def p_subscript(s):
# Parse a subscript and return a list of
# 1, 2 or 3 ExprNodes, depending on how
# many slice elements were encountered.
pos = s.position()
if s.sy == '.':
expect_ellipsis(s)
return [ExprNodes.EllipsisNode(pos)]
else:
start = p_slice_element(s, (':',))
if s.sy != ':':
return [start]
s.next()
stop = p_slice_element(s, (':', ',', ']'))
if s.sy != ':':
return [start, stop]
s.next()
step = p_slice_element(s, (':', ',', ']'))
return [start, stop, step]
def p_slice_element(s, follow_set):
# Simple expression which may be missing iff
# it is followed by something in follow_set.
if s.sy not in follow_set:
return p_test(s)
else:
return None
def expect_ellipsis(s):
s.expect('.')
s.expect('.')
s.expect('.')
def make_slice_nodes(pos, subscripts):
# Convert a list of subscripts as returned
# by p_subscript_list into a list of ExprNodes,
# creating SliceNodes for elements with 2 or
# more components.
result = []
for subscript in subscripts:
if len(subscript) == 1:
result.append(subscript[0])
else:
result.append(make_slice_node(pos, *subscript))
return result
def make_slice_node(pos, start, stop = None, step = None):
if not start:
start = ExprNodes.NoneNode(pos)
if not stop:
stop = ExprNodes.NoneNode(pos)
if not step:
step = ExprNodes.NoneNode(pos)
return ExprNodes.SliceNode(pos,
start = start, stop = stop, step = step)
#atom: '(' [yield_expr|testlist_comp] ')' | '[' [listmaker] ']' | '{' [dict_or_set_maker] '}' | '`' testlist '`' | NAME | NUMBER | STRING+
def p_atom(s):
pos = s.position()
sy = s.sy
if sy == '(':
s.next()
if s.sy == ')':
result = ExprNodes.TupleNode(pos, args = [])
elif s.sy == 'yield':
result = p_yield_expression(s)
else:
result = p_testlist_comp(s)
s.expect(')')
return result
elif sy == '[':
return p_list_maker(s)
elif sy == '{':
return p_dict_or_set_maker(s)
elif sy == '`':
return p_backquote_expr(s)
elif sy == 'INT':
value = s.systring
s.next()
unsigned = ""
longness = ""
while value[-1] in "UuLl":
if value[-1] in "Ll":
longness += "L"
else:
unsigned += "U"
value = value[:-1]
return ExprNodes.IntNode(pos,
value = value,
unsigned = unsigned,
longness = longness)
elif sy == 'FLOAT':
value = s.systring
s.next()
return ExprNodes.FloatNode(pos, value = value)
elif sy == 'IMAG':
value = s.systring[:-1]
s.next()
return ExprNodes.ImagNode(pos, value = value)
elif sy == 'BEGIN_STRING':
kind, bytes_value, unicode_value = p_cat_string_literal(s)
if kind == 'c':
return ExprNodes.CharNode(pos, value = bytes_value)
elif kind == 'u':
return ExprNodes.UnicodeNode(pos, value = unicode_value, bytes_value = bytes_value)
elif kind == 'b':
return ExprNodes.BytesNode(pos, value = bytes_value)
else:
return ExprNodes.StringNode(pos, value = bytes_value, unicode_value = unicode_value)
elif sy == 'IDENT':
name = EncodedString( s.systring )
s.next()
if name == "None":
return ExprNodes.NoneNode(pos)
elif name == "True":
return ExprNodes.BoolNode(pos, value=True)
elif name == "False":
return ExprNodes.BoolNode(pos, value=False)
elif name == "NULL":
return ExprNodes.NullNode(pos)
else:
return p_name(s, name)
else:
s.error("Expected an identifier or literal")
def p_name(s, name):
pos = s.position()
if not s.compile_time_expr and name in s.compile_time_env:
value = s.compile_time_env.lookup_here(name)
rep = repr(value)
if isinstance(value, bool):
return ExprNodes.BoolNode(pos, value = value)
elif isinstance(value, int):
return ExprNodes.IntNode(pos, value = rep)
elif isinstance(value, long):
return ExprNodes.IntNode(pos, value = rep, longness = "L")
elif isinstance(value, float):
return ExprNodes.FloatNode(pos, value = rep)
elif isinstance(value, _unicode):
return ExprNodes.UnicodeNode(pos, value = value)
elif isinstance(value, _bytes):
return ExprNodes.BytesNode(pos, value = value)
else:
error(pos, "Invalid type for compile-time constant: %s"
% value.__class__.__name__)
return ExprNodes.NameNode(pos, name = name)
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', '')
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 = [bytes_value], [unicode_value]
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")
elif next_kind != kind:
error(pos, "Cannot mix string literals of different types, expected %s'', got %s''" %
(kind, next_kind))
else:
bstrings.append(next_bytes_value)
ustrings.append(next_unicode_value)
# 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 = BytesLiteral( StringEncoding.join_bytes(bstrings) )
bytes_value.encoding = s.source_encoding
if kind in ('u', ''):
unicode_value = EncodedString( u''.join([ u for u in ustrings if u is not None ]) )
return kind, bytes_value, unicode_value
def p_opt_string_literal(s, required_type='u'):
if s.sy == 'BEGIN_STRING':
kind, bytes_value, unicode_value = p_string_literal(s, required_type)
if required_type == 'u':
return unicode_value
elif required_type == 'b':
return bytes_value
else:
s.error("internal parser configuration error")
else:
return None
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', ''). 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.
# s.sy == 'BEGIN_STRING'
pos = s.position()
is_raw = 0
is_python3_source = s.context.language_level >= 3
has_non_ASCII_literal_characters = False
kind = s.systring[:1].lower()
if kind == 'r':
kind = ''
is_raw = 1
elif kind in 'ub':
is_raw = s.systring[1:2].lower() == 'r'
elif kind != 'c':
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 == 'u':
chars = StringEncoding.UnicodeLiteralBuilder()
elif kind == '':
chars = StringEncoding.StrLiteralBuilder(s.source_encoding)
else:
chars = StringEncoding.BytesLiteralBuilder(s.source_encoding)
while 1:
s.next()
sy = s.sy
systr = 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
elif sy == 'ESCAPE':
if is_raw:
if systr == u'\\\n':
chars.append(u'\\\n')
elif systr == u'\\\"':
chars.append(u'"')
elif systr == u'\\\'':
chars.append(u"'")
else:
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
else:
c = systr[1]
if c in u"01234567":
chars.append_charval( int(systr[1:], 8) )
elif c in u"'\"\\":
chars.append(c)
elif c in u"abfnrtv":
chars.append(
StringEncoding.char_from_escape_sequence(systr))
elif c == u'\n':
pass
elif c == u'x':
chars.append_charval( int(systr[2:], 16) )
elif c in u'Uu':
if kind in ('u', ''):
chrval = int(systr[2:], 16)
if chrval > 1114111: # sys.maxunicode:
s.error("Invalid unicode escape '%s'" % systr,
pos = pos)
else:
# unicode escapes in plain byte strings are not unescaped
chrval = None
chars.append_uescape(chrval, systr)
else:
chars.append(u'\\' + systr[1:])
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 == 'NEWLINE':
chars.append(u'\n')
elif sy == 'END_STRING':
break
elif sy == 'EOF':
s.error("Unclosed string literal", pos = pos)
else:
s.error(
"Unexpected token %r:%r in string literal" %
(sy, s.systring))
if kind == 'c':
unicode_value = None
bytes_value = chars.getchar()
if len(bytes_value) != 1:
error(pos, u"invalid character literal: %r" % bytes_value)
else:
bytes_value, unicode_value = chars.getstrings()
if is_python3_source and has_non_ASCII_literal_characters:
# Python 3 forbids literal non-ASCII characters in byte strings
if kind != 'u':
s.error("bytes can only contain ASCII literal characters.", pos = pos)
bytes_value = None
s.next()
return (kind, bytes_value, unicode_value)
# list_display ::= "[" [listmaker] "]"
# listmaker ::= expression ( comp_for | ( "," expression )* [","] )
# comp_iter ::= comp_for | comp_if
# comp_for ::= "for" expression_list "in" testlist [comp_iter]
# comp_if ::= "if" test [comp_iter]
def p_list_maker(s):
# s.sy == '['
pos = s.position()
s.next()
if s.sy == ']':
s.expect(']')
return ExprNodes.ListNode(pos, args = [])
expr = p_test(s)
if s.sy == 'for':
target = ExprNodes.ListNode(pos, args = [])
append = ExprNodes.ComprehensionAppendNode(
pos, expr=expr, target=ExprNodes.CloneNode(target))
loop = p_comp_for(s, append)
s.expect(']')
return ExprNodes.ComprehensionNode(
pos, loop=loop, append=append, target=target,
# list comprehensions leak their loop variable in Py2
has_local_scope = s.context.language_level >= 3)
else:
if s.sy == ',':
s.next()
exprs = p_simple_expr_list(s, expr)
else:
exprs = [expr]
s.expect(']')
return ExprNodes.ListNode(pos, args = exprs)
def p_comp_iter(s, body):
if s.sy == 'for':
return p_comp_for(s, body)
elif s.sy == 'if':
return p_comp_if(s, body)
else:
# insert the 'append' operation into the loop
return body
def p_comp_for(s, body):
# s.sy == 'for'
pos = s.position()
s.next()
kw = p_for_bounds(s, allow_testlist=False)
kw['else_clause'] = None
kw['body'] = p_comp_iter(s, body)
return Nodes.ForStatNode(pos, **kw)
def p_comp_if(s, body):
# s.sy == 'if'
pos = s.position()
s.next()
test = p_test_nocond(s)
return Nodes.IfStatNode(pos,
if_clauses = [Nodes.IfClauseNode(pos, condition = test,
body = p_comp_iter(s, body))],
else_clause = None )
#dictmaker: test ':' test (',' test ':' test)* [',']
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 = [])
item = p_test(s)
if s.sy == ',' or s.sy == '}':
# set literal
values = [item]
while s.sy == ',':
s.next()
if s.sy == '}':
break
values.append( p_test(s) )
s.expect('}')
return ExprNodes.SetNode(pos, args=values)
elif s.sy == 'for':
# set comprehension
target = ExprNodes.SetNode(pos, args=[])
append = ExprNodes.ComprehensionAppendNode(
item.pos, expr=item, target=ExprNodes.CloneNode(target))
loop = p_comp_for(s, append)
s.expect('}')
return ExprNodes.ComprehensionNode(
pos, loop=loop, append=append, target=target)
elif s.sy == ':':
# dict literal or comprehension
key = item
s.next()
value = p_test(s)
if s.sy == 'for':
# dict comprehension
target = ExprNodes.DictNode(pos, key_value_pairs = [])
append = ExprNodes.DictComprehensionAppendNode(
item.pos, key_expr=key, value_expr=value,
target=ExprNodes.CloneNode(target))
loop = p_comp_for(s, append)
s.expect('}')
return ExprNodes.ComprehensionNode(
pos, loop=loop, append=append, target=target)
else:
# dict literal
items = [ExprNodes.DictItemNode(key.pos, key=key, value=value)]
while s.sy == ',':
s.next()
if s.sy == '}':
break
key = p_test(s)
s.expect(':')
value = p_test(s)
items.append(
ExprNodes.DictItemNode(key.pos, key=key, value=value))
s.expect('}')
return ExprNodes.DictNode(pos, key_value_pairs=items)
else:
# raise an error
s.expect('}')
return ExprNodes.DictNode(pos, key_value_pairs = [])
# NOTE: no longer in Py3 :)
def p_backquote_expr(s):
# s.sy == '`'
pos = s.position()
s.next()
args = [p_test(s)]
while s.sy == ',':
s.next()
args.append(p_test(s))
s.expect('`')
if len(args) == 1:
arg = args[0]
else:
arg = ExprNodes.TupleNode(pos, args = args)
return ExprNodes.BackquoteNode(pos, arg = arg)
def p_simple_expr_list(s, expr=None):
exprs = expr is not None and [expr] or []
while s.sy not in expr_terminators:
exprs.append( p_test(s) )
if s.sy != ',':
break
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) )
if s.sy != ',':
break
s.next()
return exprs
#testlist: test (',' test)* [',']
def p_testlist(s):
pos = s.position()
expr = p_test(s)
if s.sy == ',':
s.next()
exprs = p_simple_expr_list(s, expr)
return ExprNodes.TupleNode(pos, args = exprs)
else:
return expr
# testlist_star_expr: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] )
def p_testlist_star_expr(s):
pos = s.position()
expr = p_test_or_starred_expr(s)
if s.sy == ',':
s.next()
exprs = p_test_or_starred_expr_list(s, expr)
return ExprNodes.TupleNode(pos, args = exprs)
else:
return expr
# testlist_comp: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] )
def p_testlist_comp(s):
pos = s.position()
expr = p_test_or_starred_expr(s)
if s.sy == ',':
s.next()
exprs = p_test_or_starred_expr_list(s, expr)
return ExprNodes.TupleNode(pos, args = exprs)
elif s.sy == 'for':
return p_genexp(s, expr)
else:
return expr
def p_genexp(s, expr):
# s.sy == 'for'
loop = p_comp_for(s, Nodes.ExprStatNode(
expr.pos, expr = ExprNodes.YieldExprNode(expr.pos, arg=expr)))
return ExprNodes.GeneratorExpressionNode(expr.pos, loop=loop)
expr_terminators = (')', ']', '}', ':', '=', 'NEWLINE')
#-------------------------------------------------------
#
# Statements
#
#-------------------------------------------------------
def p_global_statement(s):
# assume s.sy == 'global'
pos = s.position()
s.next()
names = p_ident_list(s)
return Nodes.GlobalNode(pos, names = names)
def p_expression_or_assignment(s):
expr_list = [p_testlist_star_expr(s)]
while s.sy == '=':
s.next()
if s.sy == 'yield':
expr = p_yield_expression(s)
else:
expr = p_testlist_star_expr(s)
expr_list.append(expr)
if len(expr_list) == 1:
if re.match(r"([+*/\%^\&|-]|<<|>>|\*\*|//)=", s.sy):
lhs = expr_list[0]
if not isinstance(lhs, (ExprNodes.AttributeNode, ExprNodes.IndexNode, ExprNodes.NameNode) ):
error(lhs.pos, "Illegal operand for inplace operation.")
operator = s.sy[:-1]
s.next()
if s.sy == 'yield':
rhs = p_yield_expression(s)
else:
rhs = p_testlist(s)
return Nodes.InPlaceAssignmentNode(lhs.pos, operator = operator, lhs = lhs, rhs = rhs)
expr = expr_list[0]
if isinstance(expr, (ExprNodes.UnicodeNode, ExprNodes.StringNode, ExprNodes.BytesNode)):
return Nodes.PassStatNode(expr.pos)
else:
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)
else:
return Nodes.CascadedAssignmentNode(rhs.pos,
lhs_list = expr_list[:-1], rhs = rhs)
def p_print_statement(s):
# s.sy == 'print'
pos = s.position()
ends_with_comma = 0
s.next()
if s.sy == '>>':
s.next()
stream = p_test(s)
if s.sy == ',':
s.next()
ends_with_comma = s.sy in ('NEWLINE', 'EOF')
else:
stream = None
args = []
if s.sy not in ('NEWLINE', 'EOF'):
args.append(p_test(s))
while s.sy == ',':
s.next()
if s.sy in ('NEWLINE', 'EOF'):
ends_with_comma = 1
break
args.append(p_test(s))
arg_tuple = ExprNodes.TupleNode(pos, args = args)
return Nodes.PrintStatNode(pos,
arg_tuple = arg_tuple, stream = stream,
append_newline = not ends_with_comma)
def p_exec_statement(s):
# s.sy == 'exec'
pos = s.position()
s.next()
args = [ p_bit_expr(s) ]
if s.sy == 'in':
s.next()
args.append(p_test(s))
if s.sy == ',':
s.next()
args.append(p_test(s))
else:
error(pos, "'exec' currently requires a target mapping (globals/locals)")
return Nodes.ExecStatNode(pos, args = args)
def p_del_statement(s):
# s.sy == 'del'
pos = s.position()
s.next()
# FIXME: 'exprlist' in Python
args = p_simple_expr_list(s)
return Nodes.DelStatNode(pos, args = args)
def p_pass_statement(s, with_newline = 0):
pos = s.position()
s.expect('pass')
if with_newline:
s.expect_newline("Expected a newline")
return Nodes.PassStatNode(pos)
def p_break_statement(s):
# s.sy == 'break'
pos = s.position()
s.next()
return Nodes.BreakStatNode(pos)
def p_continue_statement(s):
# s.sy == 'continue'
pos = s.position()
s.next()
return Nodes.ContinueStatNode(pos)
def p_return_statement(s):
# s.sy == 'return'
pos = s.position()
s.next()
if s.sy not in statement_terminators:
value = p_testlist(s)
else:
value = None
return Nodes.ReturnStatNode(pos, value = value)
def p_raise_statement(s):
# s.sy == 'raise'
pos = s.position()
s.next()
exc_type = None
exc_value = None
exc_tb = None
if s.sy not in statement_terminators:
exc_type = p_test(s)
if s.sy == ',':
s.next()
exc_value = p_test(s)
if s.sy == ',':
s.next()
exc_tb = p_test(s)
if exc_type or exc_value or exc_tb:
return Nodes.RaiseStatNode(pos,
exc_type = exc_type,
exc_value = exc_value,
exc_tb = exc_tb)
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)]
while s.sy == ',':
s.next()
items.append(p_dotted_name(s, as_allowed = 1))
stats = []
for pos, target_name, dotted_name, as_name in items:
dotted_name = EncodedString(dotted_name)
if kind == 'cimport':
stat = Nodes.CImportStatNode(pos,
module_name = dotted_name,
as_name = as_name)
else:
if as_name and "." in dotted_name:
name_list = ExprNodes.ListNode(pos, args = [
ExprNodes.IdentifierStringNode(pos, value = EncodedString("*"))])
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),
name_list = name_list))
stats.append(stat)
return Nodes.StatListNode(pos, stats = stats)
def p_from_import_statement(s, first_statement = 0):
# s.sy == 'from'
pos = s.position()
s.next()
(dotted_name_pos, _, dotted_name, _) = \
p_dotted_name(s, as_allowed = 0)
if s.sy in ('import', 'cimport'):
kind = s.sy
s.next()
else:
s.error("Expected 'import' or 'cimport'")
is_cimport = kind == 'cimport'
is_parenthesized = False
if s.sy == '*':
imported_names = [(s.position(), "*", None, None)]
s.next()
else:
if s.sy == '(':
is_parenthesized = True
s.next()
imported_names = [p_imported_name(s, is_cimport)]
while s.sy == ',':
s.next()
if is_parenthesized and s.sy == ')':
break
imported_names.append(p_imported_name(s, is_cimport))
if is_parenthesized:
s.expect(')')
dotted_name = EncodedString(dotted_name)
if dotted_name == '__future__':
if not first_statement:
s.error("from __future__ imports must occur at the beginning of the file")
else:
for (name_pos, name, as_name, kind) in imported_names:
if name == "braces":
s.error("not a chance", name_pos)
break
try:
directive = getattr(Future, name)
except AttributeError:
s.error("future feature %s is not defined" % name, name_pos)
break
s.context.future_directives.add(directive)
return Nodes.PassStatNode(pos)
elif kind == 'cimport':
return Nodes.FromCImportStatNode(pos,
module_name = dotted_name,
imported_names = imported_names)
else:
imported_name_strings = []
items = []
for (name_pos, name, as_name, kind) in imported_names:
encoded_name = EncodedString(name)
imported_name_strings.append(
ExprNodes.IdentifierStringNode(name_pos, value = encoded_name))
items.append(
(name,
ExprNodes.NameNode(name_pos,
name = as_name or name)))
import_list = ExprNodes.ListNode(
imported_names[0][0], args = imported_name_strings)
dotted_name = EncodedString(dotted_name)
return Nodes.FromImportStatNode(pos,
module = ExprNodes.ImportNode(dotted_name_pos,
module_name = ExprNodes.IdentifierStringNode(pos, value = dotted_name),
name_list = import_list),
items = items)
imported_name_kinds = ('class', 'struct', 'union')
def p_imported_name(s, is_cimport):
pos = s.position()
kind = None
if is_cimport and s.systring in imported_name_kinds:
kind = s.systring
s.next()
name = p_ident(s)
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)
as_name = None
names = [target_name]
while s.sy == '.':
s.next()
names.append(p_ident(s))
if as_allowed:
as_name = p_as_name(s)
return (pos, target_name, u'.'.join(names), as_name)
def p_as_name(s):
if s.sy == 'IDENT' and s.systring == 'as':
s.next()
return p_ident(s)
else:
return None
def p_assert_statement(s):
# s.sy == 'assert'
pos = s.position()
s.next()
cond = p_test(s)
if s.sy == ',':
s.next()
value = p_test(s)
else:
value = None
return Nodes.AssertStatNode(pos, cond = cond, value = value)
statement_terminators = (';', 'NEWLINE', 'EOF')
def p_if_statement(s):
# s.sy == 'if'
pos = s.position()
s.next()
if_clauses = [p_if_clause(s)]
while s.sy == 'elif':
s.next()
if_clauses.append(p_if_clause(s))
else_clause = p_else_clause(s)
return Nodes.IfStatNode(pos,
if_clauses = if_clauses, else_clause = else_clause)
def p_if_clause(s):
pos = s.position()
test = p_test(s)
body = p_suite(s)
return Nodes.IfClauseNode(pos,
condition = test, body = body)
def p_else_clause(s):
if s.sy == 'else':
s.next()
return p_suite(s)
else:
return None
def p_while_statement(s):
# s.sy == 'while'
pos = s.position()
s.next()
test = p_test(s)
body = p_suite(s)
else_clause = p_else_clause(s)
return Nodes.WhileStatNode(pos,
condition = test, body = body,
else_clause = else_clause)
def p_for_statement(s):
# s.sy == 'for'
pos = s.position()
s.next()
kw = p_for_bounds(s, allow_testlist=True)
kw['body'] = p_suite(s)
kw['else_clause'] = p_else_clause(s)
return Nodes.ForStatNode(pos, **kw)
def p_for_bounds(s, allow_testlist=True):
target = p_for_target(s)
if s.sy == 'in':
s.next()
iterator = p_for_iterator(s, allow_testlist)
return { 'target': target, 'iterator': iterator }
elif not s.in_python_file:
if s.sy == 'from':
s.next()
bound1 = p_bit_expr(s)
else:
# Support shorter "for a <= x < b" syntax
bound1, target = target, None
rel1 = p_for_from_relation(s)
name2_pos = s.position()
name2 = p_ident(s)
rel2_pos = s.position()
rel2 = p_for_from_relation(s)
bound2 = p_bit_expr(s)
step = p_for_from_step(s)
if target is None:
target = ExprNodes.NameNode(name2_pos, name = name2)
else:
if not target.is_name:
error(target.pos,
"Target of for-from statement must be a variable name")
elif name2 != target.name:
error(name2_pos,
"Variable name in for-from range does not match target")
if rel1[0] != rel2[0]:
error(rel2_pos,
"Relation directions in for-from do not match")
return {'target': target,
'bound1': bound1,
'relation1': rel1,
'relation2': rel2,
'bound2': bound2,
'step': step }
else:
s.expect('in')
return {}
def p_for_from_relation(s):
if s.sy in inequality_relations:
op = s.sy
s.next()
return op
else:
s.error("Expected one of '<', '<=', '>' '>='")
def p_for_from_step(s):
if s.sy == 'by':
s.next()
step = p_bit_expr(s)
return step
else:
return None
inequality_relations = ('<', '<=', '>', '>=')
def p_target(s, terminator):
pos = s.position()
expr = p_starred_expr(s)
if s.sy == ',':
s.next()
exprs = [expr]
while s.sy != terminator:
exprs.append(p_starred_expr(s))
if s.sy != ',':
break
s.next()
return ExprNodes.TupleNode(pos, args = exprs)
else:
return expr
def p_for_target(s):
return p_target(s, 'in')
def p_for_iterator(s, allow_testlist=True):
pos = s.position()
if allow_testlist:
expr = p_testlist(s)
else:
expr = p_or_test(s)
return ExprNodes.IteratorNode(pos, sequence = expr)
def p_try_statement(s):
# s.sy == 'try'
pos = s.position()
s.next()
body = p_suite(s)
except_clauses = []
else_clause = None
if s.sy in ('except', 'else'):
while s.sy == 'except':
except_clauses.append(p_except_clause(s))
if s.sy == 'else':
s.next()
else_clause = p_suite(s)
body = Nodes.TryExceptStatNode(pos,
body = body, except_clauses = except_clauses,
else_clause = else_clause)
if s.sy != 'finally':
return body
# try-except-finally is equivalent to nested try-except/try-finally
if s.sy == 'finally':
s.next()
finally_clause = p_suite(s)
return Nodes.TryFinallyStatNode(pos,
body = body, finally_clause = finally_clause)
else:
s.error("Expected 'except' or 'finally'")
def p_except_clause(s):
# s.sy == 'except'
pos = s.position()
s.next()
exc_type = None
exc_value = None
if s.sy != ':':
exc_type = p_test(s)
# normalise into list of single exception tests
if isinstance(exc_type, ExprNodes.TupleNode):
exc_type = exc_type.args
else:
exc_type = [exc_type]
if s.sy == ',' or (s.sy == 'IDENT' and s.systring == 'as'):
s.next()
exc_value = p_test(s)
elif s.sy == 'IDENT' and s.systring == 'as':
# Py3 syntax requires a name here
s.next()
pos2 = s.position()
name = p_ident(s)
exc_value = ExprNodes.NameNode(pos2, name = name)
body = p_suite(s)
return Nodes.ExceptClauseNode(pos,
pattern = exc_type, target = exc_value, body = body)
def p_include_statement(s, ctx):
pos = s.position()
s.next() # 'include'
unicode_include_file_name = p_string_literal(s, 'u')[2]
s.expect_newline("Syntax error in include statement")
if s.compile_time_eval:
include_file_name = unicode_include_file_name
include_file_path = s.context.find_include_file(include_file_name, pos)
if include_file_path:
s.included_files.append(include_file_name)
f = Utils.open_source_file(include_file_path, mode="rU")
source_desc = FileSourceDescriptor(include_file_path)
s2 = PyrexScanner(f, source_desc, s, source_encoding=f.encoding, parse_comments=s.parse_comments)
try:
tree = p_statement_list(s2, ctx)
finally:
f.close()
return tree
else:
return None
else:
return Nodes.PassStatNode(pos)
def p_with_statement(s):
pos = s.position()
s.next() # 'with'
# if s.sy == 'IDENT' and s.systring in ('gil', 'nogil'):
if s.sy == 'IDENT' and s.systring == 'nogil':
state = s.systring
s.next()
body = p_suite(s)
return Nodes.GILStatNode(pos, state = state, body = body)
elif s.systring == 'template':
templates = []
s.next()
s.expect('[')
#s.next()
templates.append(s.systring)
s.next()
while s.systring == ',':
s.next()
templates.append(s.systring)
s.next()
s.expect(']')
if s.sy == ':':
s.next()
s.expect_newline("Syntax error in template function declaration")
s.expect_indent()
body_ctx = Ctx()
body_ctx.templates = templates
func_or_var = p_c_func_or_var_declaration(s, pos, body_ctx)
s.expect_dedent()
return func_or_var
else:
error(pos, "Syntax error in template function declaration")
else:
manager = p_test(s)
target = None
if s.sy == 'IDENT' and s.systring == 'as':
s.next()
allow_multi = (s.sy == '(')
target = p_target(s, ':')
if not allow_multi and isinstance(target, ExprNodes.TupleNode):
s.error("Multiple with statement target values not allowed without paranthesis")
body = p_suite(s)
return Nodes.WithStatNode(pos, manager = manager,
target = target, body = body)
def p_simple_statement(s, first_statement = 0):
#print "p_simple_statement:", s.sy, s.systring ###
if s.sy == 'global':
node = p_global_statement(s)
elif s.sy == 'print':
node = p_print_statement(s)
elif s.sy == 'exec':
node = p_exec_statement(s)
elif s.sy == 'del':
node = p_del_statement(s)
elif s.sy == 'break':
node = p_break_statement(s)
elif s.sy == 'continue':
node = p_continue_statement(s)
elif s.sy == 'return':
node = p_return_statement(s)
elif s.sy == 'raise':
node = p_raise_statement(s)
elif s.sy in ('import', 'cimport'):
node = p_import_statement(s)
elif s.sy == 'from':
node = p_from_import_statement(s, first_statement = first_statement)
elif s.sy == 'yield':
node = p_yield_statement(s)
elif s.sy == 'assert':
node = p_assert_statement(s)
elif s.sy == 'pass':
node = p_pass_statement(s)
else:
node = p_expression_or_assignment(s)
return node
def p_simple_statement_list(s, ctx, first_statement = 0):
# Parse a series of simple statements on one line
# separated by semicolons.
stat = p_simple_statement(s, first_statement = first_statement)
if s.sy == ';':
stats = [stat]
while s.sy == ';':
#print "p_simple_statement_list: maybe more to follow" ###
s.next()
if s.sy in ('NEWLINE', 'EOF'):
break
stats.append(p_simple_statement(s))
stat = Nodes.StatListNode(stats[0].pos, stats = stats)
s.expect_newline("Syntax error in simple statement list")
return stat
def p_compile_time_expr(s):
old = s.compile_time_expr
s.compile_time_expr = 1
expr = p_testlist(s)
s.compile_time_expr = old
return expr
def p_DEF_statement(s):
pos = s.position()
denv = s.compile_time_env
s.next() # 'DEF'
name = p_ident(s)
s.expect('=')
expr = p_compile_time_expr(s)
value = expr.compile_time_value(denv)
#print "p_DEF_statement: %s = %r" % (name, value) ###
denv.declare(name, value)
s.expect_newline()
return Nodes.PassStatNode(pos)
def p_IF_statement(s, ctx):
pos = s.position()
saved_eval = s.compile_time_eval
current_eval = saved_eval
denv = s.compile_time_env
result = None
while 1:
s.next() # 'IF' or 'ELIF'
expr = p_compile_time_expr(s)
s.compile_time_eval = current_eval and bool(expr.compile_time_value(denv))
body = p_suite(s, ctx)
if s.compile_time_eval:
result = body
current_eval = 0
if s.sy != 'ELIF':
break
if s.sy == 'ELSE':
s.next()
s.compile_time_eval = current_eval
body = p_suite(s, ctx)
if current_eval:
result = body
if not result:
result = Nodes.PassStatNode(pos)
s.compile_time_eval = saved_eval
return result
def p_statement(s, ctx, first_statement = 0):
cdef_flag = ctx.cdef_flag
decorators = None
if s.sy == 'ctypedef':
if ctx.level not in ('module', 'module_pxd'):
s.error("ctypedef statement not allowed here")
#if ctx.api:
# error(s.position(), "'api' not allowed with 'ctypedef'")
return p_ctypedef_statement(s, ctx)
elif s.sy == 'DEF':
return p_DEF_statement(s)
elif s.sy == 'IF':
return p_IF_statement(s, ctx)
elif s.sy == 'DECORATOR':
if ctx.level not in ('module', 'class', 'c_class', 'function', 'property', 'module_pxd', 'c_class_pxd'):
print ctx.level
s.error('decorator not allowed here')
s.level = ctx.level
decorators = p_decorators(s)
if s.sy not in ('def', 'cdef', 'cpdef', 'class'):
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)
overridable = 0
if s.sy == 'cdef':
cdef_flag = 1
s.next()
elif s.sy == 'cpdef':
cdef_flag = 1
overridable = 1
s.next()
if cdef_flag:
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))
if decorators is not None:
if not isinstance(node, (Nodes.CFuncDefNode, Nodes.CVarDefNode)):
s.error("Decorators can only be followed by functions or Python classes")
node.decorators = decorators
return node
else:
if ctx.api:
s.error("'api' not allowed with this statement")
elif s.sy == 'def':
# def statements aren't allowed in pxd files, except
# as part of a cdef class
if ('pxd' in ctx.level) and (ctx.level != 'c_class_pxd'):
s.error('def statement not allowed here')
s.level = ctx.level
return p_def_statement(s, decorators)
elif s.sy == 'class':
if ctx.level != 'module':
s.error("class definition not allowed here")
return p_class_statement(s, decorators)
elif s.sy == 'include':
if ctx.level not in ('module', 'module_pxd'):
s.error("include statement not allowed here")
return p_include_statement(s, ctx)
elif ctx.level == 'c_class' and s.sy == 'IDENT' and s.systring == 'property':
return p_property_decl(s)
elif s.sy == 'pass' and ctx.level != 'property':
return p_pass_statement(s, with_newline = 1)
else:
if ctx.level in ('c_class_pxd', 'property'):
s.error("Executable statement not allowed here")
if s.sy == 'if':
return p_if_statement(s)
elif s.sy == 'while':
return p_while_statement(s)
elif s.sy == 'for':
return p_for_statement(s)
elif s.sy == 'try':
return p_try_statement(s)
elif s.sy == 'with':
return p_with_statement(s)
else:
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()
stats = []
while s.sy not in ('DEDENT', 'EOF'):
stats.append(p_statement(s, ctx, first_statement = first_statement))
first_statement = 0
if len(stats) == 1:
return stats[0]
else:
return Nodes.StatListNode(pos, stats = stats)
def p_suite(s, ctx = Ctx(), with_doc = 0, with_pseudo_doc = 0):
pos = s.position()
s.expect(':')
doc = None
stmts = []
if s.sy == 'NEWLINE':
s.next()
s.expect_indent()
if with_doc or with_pseudo_doc:
doc = p_doc_string(s)
body = p_statement_list(s, ctx)
s.expect_dedent()
else:
if ctx.api:
s.error("'api' not allowed with this statement")
if ctx.level in ('module', 'class', 'function', 'other'):
body = p_simple_statement_list(s, ctx)
else:
body = p_pass_statement(s)
s.expect_newline("Syntax error in declarations")
if with_doc:
return doc, body
else:
return body
def p_positional_and_keyword_args(s, end_sy_set, templates = None):
"""
Parses positional and keyword arguments. end_sy_set
should contain any s.sy that terminate the argument list.
Argument expansion (* and **) are not allowed.
Returns: (positional_args, keyword_args)
"""
positional_args = []
keyword_args = []
pos_idx = 0
while s.sy not in end_sy_set:
if s.sy == '*' or s.sy == '**':
s.error('Argument expansion not allowed here.')
parsed_type = False
if s.sy == 'IDENT' and s.peek()[0] == '=':
ident = s.systring
s.next() # s.sy is '='
s.next()
if looking_at_expr(s):
arg = p_test(s)
else:
base_type = p_c_base_type(s, templates = templates)
declarator = p_c_declarator(s, empty = 1)
arg = Nodes.CComplexBaseTypeNode(base_type.pos,
base_type = base_type, declarator = declarator)
parsed_type = True
keyword_node = ExprNodes.IdentifierStringNode(
arg.pos, value = EncodedString(ident))
keyword_args.append((keyword_node, arg))
was_keyword = True
else:
if looking_at_expr(s):
arg = p_test(s)
else:
base_type = p_c_base_type(s, templates = templates)
declarator = p_c_declarator(s, empty = 1)
arg = Nodes.CComplexBaseTypeNode(base_type.pos,
base_type = base_type, declarator = declarator)
parsed_type = True
positional_args.append(arg)
pos_idx += 1
if len(keyword_args) > 0:
s.error("Non-keyword arg following keyword arg",
pos = arg.pos)
if s.sy != ',':
if s.sy not in end_sy_set:
if parsed_type:
s.error("Unmatched %s" % " or ".join(end_sy_set))
break
s.next()
return positional_args, keyword_args
def p_c_base_type(s, self_flag = 0, nonempty = 0, templates = None):
# If self_flag is true, this is the base type for the
# self argument of a C method of an extension type.
if s.sy == '(':
return p_c_complex_base_type(s)
else:
return p_c_simple_base_type(s, self_flag, nonempty = nonempty, templates = templates)
def p_calling_convention(s):
if s.sy == 'IDENT' and s.systring in calling_convention_words:
result = s.systring
s.next()
return result
else:
return ""
calling_convention_words = ("__stdcall", "__cdecl", "__fastcall")
def p_c_complex_base_type(s):
# s.sy == '('
pos = s.position()
s.next()
base_type = p_c_base_type(s)
declarator = p_c_declarator(s, empty = 1)
s.expect(')')
return Nodes.CComplexBaseTypeNode(pos,
base_type = base_type, declarator = declarator)
def p_c_simple_base_type(s, self_flag, nonempty, templates = None):
#print "p_c_simple_base_type: self_flag =", self_flag, nonempty
is_basic = 0
signed = 1
longness = 0
complex = 0
module_path = []
pos = s.position()
if not s.sy == 'IDENT':
error(pos, "Expected an identifier, found '%s'" % s.sy)
if looking_at_base_type(s):
#print "p_c_simple_base_type: looking_at_base_type at", s.position()
is_basic = 1
if s.sy == 'IDENT' and s.systring in special_basic_c_types:
signed, longness = special_basic_c_types[s.systring]
name = s.systring
s.next()
else:
signed, longness = p_sign_and_longness(s)
if s.sy == 'IDENT' and s.systring in basic_c_type_names:
name = s.systring
s.next()
else:
name = 'int'
if s.sy == 'IDENT' and s.systring == 'complex':
complex = 1
s.next()
elif looking_at_dotted_name(s):
#print "p_c_simple_base_type: looking_at_type_name at", s.position()
name = s.systring
s.next()
while s.sy == '.':
module_path.append(name)
s.next()
name = p_ident(s)
else:
name = s.systring
s.next()
if nonempty and s.sy != 'IDENT':
# Make sure this is not a declaration of a variable or function.
if s.sy == '(':
s.next()
if s.sy == '*' or s.sy == '**' or s.sy == '&':
s.put_back('(', '(')
else:
s.put_back('(', '(')
s.put_back('IDENT', name)
name = None
elif s.sy not in ('*', '**', '[', '&'):
s.put_back('IDENT', name)
name = None
type_node = Nodes.CSimpleBaseTypeNode(pos,
name = name, module_path = module_path,
is_basic_c_type = is_basic, signed = signed,
complex = complex, longness = longness,
is_self_arg = self_flag, templates = templates)
if s.sy == '[':
type_node = p_buffer_or_template(s, type_node, templates)
if s.sy == '.':
s.next()
name = p_ident(s)
type_node = Nodes.CNestedBaseTypeNode(pos, base_type = type_node, name = name)
return type_node
def p_buffer_or_template(s, base_type_node, templates):
# s.sy == '['
pos = s.position()
s.next()
# Note that buffer_positional_options_count=1, so the only positional argument is dtype.
# For templated types, all parameters are types.
positional_args, keyword_args = (
p_positional_and_keyword_args(s, (']',), templates)
)
s.expect(']')
keyword_dict = ExprNodes.DictNode(pos,
key_value_pairs = [
ExprNodes.DictItemNode(pos=key.pos, key=key, value=value)
for key, value in keyword_args
])
result = Nodes.TemplatedTypeNode(pos,
positional_args = positional_args,
keyword_args = keyword_dict,
base_type_node = base_type_node)
return result
def looking_at_name(s):
return s.sy == 'IDENT' and not s.systring in calling_convention_words
def looking_at_expr(s):
if s.systring in base_type_start_words:
return False
elif s.sy == 'IDENT':
is_type = False
name = s.systring
dotted_path = []
s.next()
while s.sy == '.':
s.next()
dotted_path.append(s.systring)
s.expect('IDENT')
saved = s.sy, s.systring
if s.sy == 'IDENT':
is_type = True
elif s.sy == '*' or s.sy == '**':
s.next()
is_type = s.sy == ')'
s.put_back(*saved)
elif s.sy == '(':
s.next()
is_type = s.sy == '*'
s.put_back(*saved)
elif s.sy == '[':
s.next()
is_type = s.sy == ']'
s.put_back(*saved)
dotted_path.reverse()
for p in dotted_path:
s.put_back('IDENT', p)
s.put_back('.', '.')
s.put_back('IDENT', name)
return not is_type
else:
return True
def looking_at_base_type(s):
#print "looking_at_base_type?", s.sy, s.systring, s.position()
return s.sy == 'IDENT' and s.systring in base_type_start_words
def looking_at_dotted_name(s):
if s.sy == 'IDENT':
name = s.systring
s.next()
result = s.sy == '.'
s.put_back('IDENT', name)
return result
else:
return 0
basic_c_type_names = ("void", "char", "int", "float", "double", "bint")
special_basic_c_types = {
# name : (signed, longness)
"Py_UNICODE" : (0, 0),
"Py_ssize_t" : (2, 0),
"ssize_t" : (2, 0),
"size_t" : (0, 0),
}
sign_and_longness_words = ("short", "long", "signed", "unsigned")
base_type_start_words = \
basic_c_type_names + sign_and_longness_words + tuple(special_basic_c_types)
def p_sign_and_longness(s):
signed = 1
longness = 0
while s.sy == 'IDENT' and s.systring in sign_and_longness_words:
if s.systring == 'unsigned':
signed = 0
elif s.systring == 'signed':
signed = 2
elif s.systring == 'short':
longness = -1
elif s.systring == 'long':
longness += 1
s.next()
return signed, longness
def p_opt_cname(s):
literal = p_opt_string_literal(s, 'u')
if literal is not None:
cname = EncodedString(literal)
cname.encoding = s.source_encoding
else:
cname = None
return cname
def p_c_declarator(s, ctx = Ctx(), empty = 0, is_type = 0, cmethod_flag = 0,
assignable = 0, nonempty = 0,
calling_convention_allowed = 0):
# If empty is true, the declarator must be empty. If nonempty is true,
# the declarator must be nonempty. Otherwise we don't care.
# If cmethod_flag is true, then if this declarator declares
# a function, it's a C method of an extension type.
pos = s.position()
if s.sy == '(':
s.next()
if s.sy == ')' or looking_at_name(s):
base = Nodes.CNameDeclaratorNode(pos, name = EncodedString(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,
cmethod_flag = cmethod_flag,
nonempty = nonempty,
calling_convention_allowed = 1)
s.expect(')')
else:
result = p_c_simple_declarator(s, ctx, empty, is_type, cmethod_flag,
assignable, nonempty)
if not calling_convention_allowed and result.calling_convention and s.sy != '(':
error(s.position(), "%s on something that is not a function"
% result.calling_convention)
while s.sy in ('[', '('):
pos = s.position()
if s.sy == '[':
result = p_c_array_declarator(s, result)
else: # sy == '('
s.next()
result = p_c_func_declarator(s, pos, ctx, result, cmethod_flag)
cmethod_flag = 0
return result
def p_c_array_declarator(s, base):
pos = s.position()
s.next() # '['
if s.sy != ']':
dim = p_testlist(s)
else:
dim = None
s.expect(']')
return Nodes.CArrayDeclaratorNode(pos, base = base, dimension = dim)
def p_c_func_declarator(s, pos, ctx, base, cmethod_flag):
# Opening paren has already been skipped
args = p_c_arg_list(s, ctx, cmethod_flag = cmethod_flag,
nonempty_declarators = 0)
ellipsis = p_optional_ellipsis(s)
s.expect(')')
nogil = p_nogil(s)
exc_val, exc_check = p_exception_value_clause(s)
with_gil = p_with_gil(s)
return Nodes.CFuncDeclaratorNode(pos,
base = base, args = args, has_varargs = ellipsis,
exception_value = exc_val, exception_check = exc_check,
nogil = nogil or ctx.nogil or with_gil, with_gil = with_gil)
supported_overloaded_operators = cython.set([
'+', '-', '*', '/', '%',
'++', '--', '~', '|', '&', '^', '<<', '>>', ',',
'==', '!=', '>=', '>', '<=', '<',
'[]', '()',
])
def p_c_simple_declarator(s, ctx, empty, is_type, cmethod_flag,
assignable, nonempty):
pos = s.position()
calling_convention = p_calling_convention(s)
if s.sy == '*':
s.next()
base = p_c_declarator(s, ctx, empty = empty, is_type = is_type,
cmethod_flag = cmethod_flag,
assignable = assignable, nonempty = nonempty)
result = Nodes.CPtrDeclaratorNode(pos,
base = base)
elif s.sy == '**': # scanner returns this as a single token
s.next()
base = p_c_declarator(s, ctx, empty = empty, is_type = is_type,
cmethod_flag = cmethod_flag,
assignable = assignable, nonempty = nonempty)
result = Nodes.CPtrDeclaratorNode(pos,
base = Nodes.CPtrDeclaratorNode(pos,
base = base))
elif s.sy == '&':
s.next()
base = p_c_declarator(s, ctx, empty = empty, is_type = is_type,
cmethod_flag = cmethod_flag,
assignable = assignable, nonempty = nonempty)
result = Nodes.CReferenceDeclaratorNode(pos, base = base)
else:
rhs = None
if s.sy == 'IDENT':
name = EncodedString(s.systring)
if empty:
error(s.position(), "Declarator should be empty")
s.next()
cname = p_opt_cname(s)
if name != 'operator' and s.sy == '=' and assignable:
s.next()
rhs = p_test(s)
else:
if nonempty:
error(s.position(), "Empty declarator")
name = ""
cname = None
if cname is None and ctx.namespace is not None and nonempty:
cname = ctx.namespace + "::" + name
if name == 'operator' and ctx.visibility == 'extern' and nonempty:
op = s.sy
if [c in '+-*/<=>!%&|([^~,' for c in op]:
s.next()
# Handle diphthong operators.
if op == '(':
s.expect(')')
op = '()'
elif op == '[':
s.expect(']')
op = '[]'
if op in ['-', '+', '|', '&'] and s.sy == op:
op = op*2
s.next()
if s.sy == '=':
op += s.sy
s.next()
if op not in supported_overloaded_operators:
s.error("Overloading operator '%s' not yet supported." % op)
name = name+op
result = Nodes.CNameDeclaratorNode(pos,
name = name, cname = cname, default = rhs)
result.calling_convention = calling_convention
return result
def p_nogil(s):
if s.sy == 'IDENT' and s.systring == 'nogil':
s.next()
return 1
else:
return 0
def p_with_gil(s):
if s.sy == 'with':
s.next()
s.expect_keyword('gil')
return 1
else:
return 0
def p_exception_value_clause(s):
exc_val = None
exc_check = 0
if s.sy == 'except':
s.next()
if s.sy == '*':
exc_check = 1
s.next()
elif s.sy == '+':
exc_check = '+'
s.next()
if s.sy == 'IDENT':
name = s.systring
s.next()
exc_val = p_name(s, name)
else:
if s.sy == '?':
exc_check = 1
s.next()
exc_val = p_test(s)
return exc_val, exc_check
c_arg_list_terminators = ('*', '**', '.', ')')
def p_c_arg_list(s, ctx = Ctx(), in_pyfunc = 0, cmethod_flag = 0,
nonempty_declarators = 0, kw_only = 0, annotated = 1):
# Comma-separated list of C argument declarations, possibly empty.
# May have a trailing comma.
args = []
is_self_arg = cmethod_flag
while s.sy not in c_arg_list_terminators:
args.append(p_c_arg_decl(s, ctx, in_pyfunc, is_self_arg,
nonempty = nonempty_declarators, kw_only = kw_only,
annotated = annotated))
if s.sy != ',':
break
s.next()
is_self_arg = 0
return args
def p_optional_ellipsis(s):
if s.sy == '.':
expect_ellipsis(s)
return 1
else:
return 0
def p_c_arg_decl(s, ctx, in_pyfunc, cmethod_flag = 0, nonempty = 0,
kw_only = 0, annotated = 1):
pos = s.position()
not_none = or_none = 0
default = None
annotation = None
if s.in_python_file:
# empty type declaration
base_type = Nodes.CSimpleBaseTypeNode(pos,
name = None, module_path = [],
is_basic_c_type = 0, signed = 0,
complex = 0, longness = 0,
is_self_arg = cmethod_flag, templates = None)
else:
base_type = p_c_base_type(s, cmethod_flag, nonempty = nonempty)
declarator = p_c_declarator(s, ctx, nonempty = nonempty)
if s.sy in ('not', 'or') and not s.in_python_file:
kind = s.sy
s.next()
if s.sy == 'IDENT' and s.systring == 'None':
s.next()
else:
s.error("Expected 'None'")
if not in_pyfunc:
error(pos, "'%s None' only allowed in Python functions" % kind)
or_none = kind == 'or'
not_none = kind == 'not'
if annotated and s.sy == ':':
s.next()
annotation = p_test(s)
if s.sy == '=':
s.next()
if 'pxd' in s.level:
if s.sy not in ['*', '?']:
error(pos, "default values cannot be specified in pxd files, use ? or *")
default = ExprNodes.BoolNode(1)
s.next()
else:
default = p_test(s)
return Nodes.CArgDeclNode(pos,
base_type = base_type,
declarator = declarator,
not_none = not_none,
or_none = or_none,
default = default,
annotation = annotation,
kw_only = kw_only)
def p_api(s):
if s.sy == 'IDENT' and s.systring == 'api':
s.next()
return 1
else:
return 0
def p_cdef_statement(s, ctx):
pos = s.position()
ctx.visibility = p_visibility(s, ctx.visibility)
ctx.api = ctx.api or p_api(s)
if ctx.api:
if ctx.visibility not in ('private', 'public'):
error(pos, "Cannot combine 'api' with '%s'" % ctx.visibility)
if (ctx.visibility == 'extern') and s.sy == 'from':
return p_cdef_extern_block(s, pos, ctx)
elif s.sy == 'import':
s.next()
return p_cdef_extern_block(s, pos, ctx)
elif p_nogil(s):
ctx.nogil = 1
if ctx.overridable:
error(pos, "cdef blocks cannot be declared cpdef")
return p_cdef_block(s, ctx)
elif s.sy == ':':
if ctx.overridable:
error(pos, "cdef blocks cannot be declared cpdef")
return p_cdef_block(s, ctx)
elif s.sy == 'class':
if ctx.level not in ('module', 'module_pxd'):
error(pos, "Extension type definition not allowed here")
if ctx.overridable:
error(pos, "Extension types cannot be declared cpdef")
return p_c_class_definition(s, pos, ctx)
elif s.sy == 'IDENT' and s.systring == 'cppclass':
if ctx.visibility != 'extern':
error(pos, "C++ classes need to be declared extern")
return p_cpp_class_definition(s, pos, ctx)
elif s.sy == 'IDENT' and s.systring in ("struct", "union", "enum", "packed"):
if ctx.level not in ('module', 'module_pxd'):
error(pos, "C struct/union/enum definition not allowed here")
if ctx.overridable:
error(pos, "C struct/union/enum cannot be declared cpdef")
if s.systring == "enum":
return p_c_enum_definition(s, pos, ctx)
else:
return p_c_struct_or_union_definition(s, pos, ctx)
else:
return p_c_func_or_var_declaration(s, pos, ctx)
def p_cdef_block(s, ctx):
return p_suite(s, ctx(cdef_flag = 1))
def p_cdef_extern_block(s, pos, ctx):
if ctx.overridable:
error(pos, "cdef extern blocks cannot be declared cpdef")
include_file = None
s.expect('from')
if s.sy == '*':
s.next()
else:
include_file = p_string_literal(s, 'u')[2]
ctx = ctx(cdef_flag = 1, visibility = 'extern')
if s.systring == "namespace":
s.next()
ctx.namespace = p_string_literal(s, 'u')[2]
if p_nogil(s):
ctx.nogil = 1
body = p_suite(s, ctx)
return Nodes.CDefExternNode(pos,
include_file = include_file,
body = body,
namespace = ctx.namespace)
def p_c_enum_definition(s, pos, ctx):
# s.sy == ident 'enum'
s.next()
if s.sy == 'IDENT':
name = s.systring
s.next()
cname = p_opt_cname(s)
if cname is None and ctx.namespace is not None:
cname = ctx.namespace + "::" + name
else:
name = None
cname = None
items = None
s.expect(':')
items = []
if s.sy != 'NEWLINE':
p_c_enum_line(s, ctx, items)
else:
s.next() # 'NEWLINE'
s.expect_indent()
while s.sy not in ('DEDENT', 'EOF'):
p_c_enum_line(s, ctx, items)
s.expect_dedent()
return Nodes.CEnumDefNode(
pos, name = name, cname = cname, items = items,
typedef_flag = ctx.typedef_flag, visibility = ctx.visibility,
in_pxd = ctx.level == 'module_pxd')
def p_c_enum_line(s, ctx, items):
if s.sy != 'pass':
p_c_enum_item(s, ctx, items)
while s.sy == ',':
s.next()
if s.sy in ('NEWLINE', 'EOF'):
break
p_c_enum_item(s, ctx, items)
else:
s.next()
s.expect_newline("Syntax error in enum item list")
def p_c_enum_item(s, ctx, items):
pos = s.position()
name = p_ident(s)
cname = p_opt_cname(s)
if cname is None and ctx.namespace is not None:
cname = ctx.namespace + "::" + name
value = None
if s.sy == '=':
s.next()
value = p_test(s)
items.append(Nodes.CEnumDefItemNode(pos,
name = name, cname = cname, value = value))
def p_c_struct_or_union_definition(s, pos, ctx):
packed = False
if s.systring == 'packed':
packed = True
s.next()
if s.sy != 'IDENT' or s.systring != 'struct':
s.expected('struct')
# s.sy == ident 'struct' or 'union'
kind = s.systring
s.next()
name = p_ident(s)
cname = p_opt_cname(s)
if cname is None and ctx.namespace is not None:
cname = ctx.namespace + "::" + name
attributes = None
if s.sy == ':':
s.next()
s.expect('NEWLINE')
s.expect_indent()
attributes = []
body_ctx = Ctx()
while s.sy != 'DEDENT':
if s.sy != 'pass':
attributes.append(
p_c_func_or_var_declaration(s, s.position(), body_ctx))
else:
s.next()
s.expect_newline("Expected a newline")
s.expect_dedent()
else:
s.expect_newline("Syntax error in struct or union definition")
return Nodes.CStructOrUnionDefNode(pos,
name = name, cname = cname, kind = kind, attributes = attributes,
typedef_flag = ctx.typedef_flag, visibility = ctx.visibility,
in_pxd = ctx.level == 'module_pxd', packed = packed)
def p_visibility(s, prev_visibility):
pos = s.position()
visibility = prev_visibility
if s.sy == 'IDENT' and s.systring in ('extern', 'public', 'readonly'):
visibility = s.systring
if prev_visibility != 'private' and visibility != prev_visibility:
s.error("Conflicting visibility options '%s' and '%s'"
% (prev_visibility, visibility))
s.next()
return visibility
def p_c_modifiers(s):
if s.sy == 'IDENT' and s.systring in ('inline',):
modifier = s.systring
s.next()
return [modifier] + p_c_modifiers(s)
return []
def p_c_func_or_var_declaration(s, pos, ctx):
cmethod_flag = ctx.level in ('c_class', 'c_class_pxd')
modifiers = p_c_modifiers(s)
base_type = p_c_base_type(s, nonempty = 1, templates = ctx.templates)
declarator = p_c_declarator(s, ctx, cmethod_flag = cmethod_flag,
assignable = 1, nonempty = 1)
declarator.overridable = ctx.overridable
if s.sy == ':':
if ctx.level not in ('module', 'c_class', 'module_pxd', 'c_class_pxd') and not ctx.templates:
s.error("C function definition not allowed here")
doc, suite = p_suite(s, Ctx(level = 'function'), with_doc = 1)
result = Nodes.CFuncDefNode(pos,
visibility = ctx.visibility,
base_type = base_type,
declarator = declarator,
body = suite,
doc = doc,
modifiers = modifiers,
api = ctx.api,
overridable = ctx.overridable)
else:
#if api:
# s.error("'api' not allowed with variable declaration")
declarators = [declarator]
while s.sy == ',':
s.next()
if s.sy == 'NEWLINE':
break
declarator = p_c_declarator(s, ctx, cmethod_flag = cmethod_flag,
assignable = 1, nonempty = 1)
declarators.append(declarator)
s.expect_newline("Syntax error in C variable declaration")
result = Nodes.CVarDefNode(pos,
visibility = ctx.visibility,
base_type = base_type,
declarators = declarators,
in_pxd = ctx.level == 'module_pxd',
api = ctx.api,
overridable = ctx.overridable)
return result
def p_ctypedef_statement(s, ctx):
# s.sy == 'ctypedef'
pos = s.position()
s.next()
visibility = p_visibility(s, ctx.visibility)
api = p_api(s)
ctx = ctx(typedef_flag = 1, visibility = visibility)
if api:
ctx.api = 1
if s.sy == 'class':
return p_c_class_definition(s, pos, ctx)
elif s.sy == 'IDENT' and s.systring in ('packed', 'struct', 'union', 'enum'):
if s.systring == 'enum':
return p_c_enum_definition(s, pos, ctx)
else:
return p_c_struct_or_union_definition(s, pos, ctx)
else:
base_type = p_c_base_type(s, nonempty = 1)
if base_type.name is None:
s.error("Syntax error in ctypedef statement")
declarator = p_c_declarator(s, ctx, is_type = 1, nonempty = 1)
s.expect_newline("Syntax error in ctypedef statement")
return Nodes.CTypeDefNode(
pos, base_type = base_type,
declarator = declarator, visibility = visibility,
in_pxd = ctx.level == 'module_pxd')
def p_decorators(s):
decorators = []
while s.sy == 'DECORATOR':
pos = s.position()
s.next()
decstring = p_dotted_name(s, as_allowed=0)[2]
names = decstring.split('.')
decorator = ExprNodes.NameNode(pos, name=EncodedString(names[0]))
for name in names[1:]:
decorator = ExprNodes.AttributeNode(pos,
attribute=EncodedString(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 p_def_statement(s, decorators=None):
# s.sy == 'def'
pos = s.position()
s.next()
name = EncodedString( p_ident(s) )
s.expect('(');
args, star_arg, starstar_arg = p_varargslist(s, terminator=')')
s.expect(')')
if p_nogil(s):
error(pos, "Python function cannot be declared nogil")
return_type_annotation = None
if s.sy == '->':
s.next()
return_type_annotation = p_test(s)
doc, body = p_suite(s, Ctx(level = 'function'), with_doc = 1)
return Nodes.DefNode(pos, name = name, args = args,
star_arg = star_arg, starstar_arg = starstar_arg,
doc = doc, body = body, decorators = decorators,
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)
star_arg = None
starstar_arg = None
if s.sy == '*':
s.next()
if s.sy == 'IDENT':
star_arg = p_py_arg_decl(s)
if s.sy == ',':
s.next()
args.extend(p_c_arg_list(s, in_pyfunc = 1,
nonempty_declarators = 1, kw_only = 1))
elif s.sy != terminator:
s.error("Syntax error in Python function argument list")
if s.sy == '**':
s.next()
starstar_arg = p_py_arg_decl(s)
return (args, star_arg, starstar_arg)
def p_py_arg_decl(s):
pos = s.position()
name = p_ident(s)
annotation = None
if s.sy == ':':
s.next()
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
if s.sy == '(':
s.next()
base_list = p_simple_expr_list(s)
s.expect(')')
else:
base_list = []
doc, body = p_suite(s, Ctx(level = 'class'), with_doc = 1)
return Nodes.PyClassDefNode(pos,
name = class_name,
bases = ExprNodes.TupleNode(pos, args = base_list),
doc = doc, body = body, decorators = decorators)
def p_c_class_definition(s, pos, ctx):
# s.sy == 'class'
s.next()
module_path = []
class_name = p_ident(s)
while s.sy == '.':
s.next()
module_path.append(class_name)
class_name = p_ident(s)
if module_path and ctx.visibility != 'extern':
error(pos, "Qualified class name only allowed for 'extern' C class")
if module_path and s.sy == 'IDENT' and s.systring == 'as':
s.next()
as_name = p_ident(s)
else:
as_name = class_name
objstruct_name = None
typeobj_name = None
base_class_module = None
base_class_name = None
if s.sy == '(':
s.next()
base_class_path = [p_ident(s)]
while s.sy == '.':
s.next()
base_class_path.append(p_ident(s))
if s.sy == ',':
s.error("C class may only have one base class")
s.expect(')')
base_class_module = ".".join(base_class_path[:-1])
base_class_name = base_class_path[-1]
if s.sy == '[':
if ctx.visibility not in ('public', 'extern'):
error(s.position(), "Name options only allowed for 'public' or 'extern' C class")
objstruct_name, typeobj_name = p_c_class_options(s)
if s.sy == ':':
if ctx.level == 'module_pxd':
body_level = 'c_class_pxd'
else:
body_level = 'c_class'
doc, body = p_suite(s, Ctx(level = body_level), with_doc = 1)
else:
s.expect_newline("Syntax error in C class definition")
doc = None
body = None
if ctx.visibility == 'extern':
if not module_path:
error(pos, "Module name required for 'extern' C class")
if typeobj_name:
error(pos, "Type object name specification not allowed for 'extern' C class")
elif ctx.visibility == 'public':
if not objstruct_name:
error(pos, "Object struct name specification required for 'public' C class")
if not typeobj_name:
error(pos, "Type object name specification required for 'public' C class")
elif ctx.visibility == 'private':
if ctx.api:
error(pos, "Only 'public' C class can be declared 'api'")
else:
error(pos, "Invalid class visibility '%s'" % ctx.visibility)
return Nodes.CClassDefNode(pos,
visibility = ctx.visibility,
typedef_flag = ctx.typedef_flag,
api = ctx.api,
module_name = ".".join(module_path),
class_name = class_name,
as_name = as_name,
base_class_module = base_class_module,
base_class_name = base_class_name,
objstruct_name = objstruct_name,
typeobj_name = typeobj_name,
in_pxd = ctx.level == 'module_pxd',
doc = doc,
body = body)
def p_c_class_options(s):
objstruct_name = None
typeobj_name = None
s.expect('[')
while 1:
if s.sy != 'IDENT':
break
if s.systring == 'object':
s.next()
objstruct_name = p_ident(s)
elif s.systring == 'type':
s.next()
typeobj_name = p_ident(s)
if s.sy != ',':
break
s.next()
s.expect(']', "Expected 'object' or 'type'")
return objstruct_name, typeobj_name
def p_property_decl(s):
pos = s.position()
s.next() # 'property'
name = p_ident(s)
doc, body = p_suite(s, Ctx(level = 'property'), with_doc = 1)
return Nodes.PropertyNode(pos, name = name, doc = doc, body = body)
def p_doc_string(s):
if s.sy == 'BEGIN_STRING':
pos = s.position()
kind, bytes_result, unicode_result = p_cat_string_literal(s)
if s.sy != 'EOF':
s.expect_newline("Syntax error in doc string")
if kind in ('u', ''):
return unicode_result
warning(pos, "Python 3 requires docstrings to be unicode strings")
return bytes_result
else:
return None
def p_code(s, level=None):
body = p_statement_list(s, Ctx(level = level), first_statement = 1)
if s.sy != 'EOF':
s.error("Syntax error in statement [%s,%s]" % (
repr(s.sy), repr(s.systring)))
return body
COMPILER_DIRECTIVE_COMMENT_RE = re.compile(r"^#\s*cython:\s*((\w|[.])+\s*=.*)$")
def p_compiler_directive_comments(s):
result = {}
while s.sy == 'commentline':
m = COMPILER_DIRECTIVE_COMMENT_RE.match(s.systring)
if m:
directives = m.group(1).strip()
try:
result.update( Options.parse_directive_list(
directives, ignore_unknown=True) )
except ValueError, e:
s.error(e.args[0], fatal=False)
s.next()
return result
def p_module(s, pxd, full_module_name):
pos = s.position()
directive_comments = p_compiler_directive_comments(s)
s.parse_comments = False
if 'language_level' in directive_comments:
s.context.set_language_level(directive_comments['language_level'])
doc = p_doc_string(s)
if pxd:
level = 'module_pxd'
else:
level = 'module'
body = p_statement_list(s, Ctx(level = level), first_statement = 1)
if s.sy != 'EOF':
s.error("Syntax error in statement [%s,%s]" % (
repr(s.sy), repr(s.systring)))
return ModuleNode(pos, doc = doc, body = body,
full_module_name = full_module_name,
directive_comments = directive_comments)
def p_cpp_class_definition(s, pos, ctx):
# s.sy == 'cppclass'
s.next()
module_path = []
class_name = p_ident(s)
cname = p_opt_cname(s)
if cname is None and ctx.namespace is not None:
cname = ctx.namespace + "::" + class_name
if s.sy == '.':
error(pos, "Qualified class name not allowed C++ class")
if s.sy == '[':
s.next()
templates = [p_ident(s)]
while s.sy == ',':
s.next()
templates.append(p_ident(s))
s.expect(']')
else:
templates = None
if s.sy == '(':
s.next()
base_classes = [p_dotted_name(s, False)[2]]
while s.sy == ',':
s.next()
base_classes.append(p_dotted_name(s, False)[2])
s.expect(')')
else:
base_classes = []
if s.sy == '[':
error(s.position(), "Name options not allowed for C++ class")
if s.sy == ':':
s.next()
s.expect('NEWLINE')
s.expect_indent()
attributes = []
body_ctx = Ctx(visibility = ctx.visibility)
body_ctx.templates = templates
while s.sy != 'DEDENT':
if s.systring == 'cppclass':
attributes.append(
p_cpp_class_definition(s, s.position(), body_ctx))
elif s.sy != 'pass':
attributes.append(
p_c_func_or_var_declaration(s, s.position(), body_ctx))
else:
s.next()
s.expect_newline("Expected a newline")
s.expect_dedent()
else:
attributes = None
s.expect_newline("Syntax error in C++ class definition")
return Nodes.CppClassNode(pos,
name = class_name,
cname = cname,
base_classes = base_classes,
visibility = ctx.visibility,
in_pxd = ctx.level == 'module_pxd',
attributes = attributes,
templates = templates)
#----------------------------------------------
#
# Debugging
#
#----------------------------------------------
def print_parse_tree(f, node, level, key = None):
from types import ListType, TupleType
from Nodes import Node
ind = " " * level
if node:
f.write(ind)
if key:
f.write("%s: " % key)
t = type(node)
if t is tuple:
f.write("(%s @ %s\n" % (node[0], node[1]))
for i in xrange(2, len(node)):
print_parse_tree(f, node[i], level+1)
f.write("%s)\n" % ind)
return
elif isinstance(node, Node):
try:
tag = node.tag
except AttributeError:
tag = node.__class__.__name__
f.write("%s @ %s\n" % (tag, node.pos))
for name, value in node.__dict__.items():
if name != 'tag' and name != 'pos':
print_parse_tree(f, value, level+1, name)
return
elif t is list:
f.write("[\n")
for i in xrange(len(node)):
print_parse_tree(f, node[i], level+1)
f.write("%s]\n" % ind)
return
f.write("%s%s\n" % (ind, node))
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/PyrexTypes.py 0000775 0000000 0000000 00000265227 11446142532 0025511 0 ustar 00root root 0000000 0000000 #
# Pyrex - Types
#
from Code import UtilityCode
import StringEncoding
import Naming
import copy
from Errors import error
class BaseType(object):
#
# Base class for all Pyrex types including pseudo-types.
def can_coerce_to_pyobject(self, env):
return False
def cast_code(self, expr_code):
return "((%s)%s)" % (self.declaration_code(""), expr_code)
def specialization_name(self):
return self.declaration_code("").replace(" ", "__")
def base_declaration_code(self, base_code, entity_code):
if entity_code:
return "%s %s" % (base_code, entity_code)
else:
return base_code
class PyrexType(BaseType):
#
# Base class for all Pyrex types.
#
# is_pyobject boolean Is a Python object type
# is_extension_type boolean Is a Python extension type
# is_numeric boolean Is a C numeric type
# is_int boolean Is a C integer type
# is_float boolean Is a C floating point type
# is_complex boolean Is a C complex type
# is_void boolean Is the C void type
# is_array boolean Is a C array type
# is_ptr boolean Is a C pointer type
# is_null_ptr boolean Is the type of NULL
# is_reference boolean Is a C reference type
# is_cfunction boolean Is a C function type
# is_struct_or_union boolean Is a C struct or union type
# is_struct boolean Is a C struct type
# is_enum boolean Is a C enum type
# is_typedef boolean Is a typedef type
# is_string boolean Is a C char * type
# is_unicode boolean Is a UTF-8 encoded C char * type
# is_returncode boolean Is used only to signal exceptions
# is_error boolean Is the dummy error type
# is_buffer boolean Is buffer access type
# has_attributes boolean Has C dot-selectable attributes
# default_value string Initial value
#
# declaration_code(entity_code,
# for_display = 0, dll_linkage = None, pyrex = 0)
# Returns a code fragment for the declaration of an entity
# of this type, given a code fragment for the entity.
# * If for_display, this is for reading by a human in an error
# message; otherwise it must be valid C code.
# * If dll_linkage is not None, it must be 'DL_EXPORT' or
# 'DL_IMPORT', and will be added to the base type part of
# the declaration.
# * If pyrex = 1, this is for use in a 'cdef extern'
# statement of a Pyrex include file.
#
# assignable_from(src_type)
# Tests whether a variable of this type can be
# assigned a value of type src_type.
#
# same_as(other_type)
# Tests whether this type represents the same type
# as other_type.
#
# as_argument_type():
# Coerces array type into pointer type for use as
# a formal argument type.
#
is_pyobject = 0
is_unspecified = 0
is_extension_type = 0
is_builtin_type = 0
is_numeric = 0
is_int = 0
is_float = 0
is_complex = 0
is_void = 0
is_array = 0
is_ptr = 0
is_null_ptr = 0
is_reference = 0
is_cfunction = 0
is_struct_or_union = 0
is_cpp_class = 0
is_struct = 0
is_enum = 0
is_typedef = 0
is_string = 0
is_unicode = 0
is_returncode = 0
is_error = 0
is_buffer = 0
has_attributes = 0
default_value = ""
def resolve(self):
# If a typedef, returns the base type.
return self
def specialize(self, values):
# TODO(danilo): Override wherever it makes sense.
return self
def literal_code(self, value):
# Returns a C code fragment representing a literal
# value of this type.
return str(value)
def __str__(self):
return self.declaration_code("", for_display = 1).strip()
def same_as(self, other_type, **kwds):
return self.same_as_resolved_type(other_type.resolve(), **kwds)
def same_as_resolved_type(self, other_type):
return self == other_type or other_type is error_type
def subtype_of(self, other_type):
return self.subtype_of_resolved_type(other_type.resolve())
def subtype_of_resolved_type(self, other_type):
return self.same_as(other_type)
def assignable_from(self, src_type):
return self.assignable_from_resolved_type(src_type.resolve())
def assignable_from_resolved_type(self, src_type):
return self.same_as(src_type)
def as_argument_type(self):
return self
def is_complete(self):
# A type is incomplete if it is an unsized array,
# a struct whose attributes are not defined, etc.
return 1
def is_simple_buffer_dtype(self):
return (self.is_int or self.is_float or self.is_complex or self.is_pyobject or
self.is_extension_type or self.is_ptr)
def struct_nesting_depth(self):
# Returns the number levels of nested structs. This is
# used for constructing a stack for walking the run-time
# type information of the struct.
return 1
def public_decl(base_code, dll_linkage):
if dll_linkage:
return "%s(%s)" % (dll_linkage, base_code)
else:
return base_code
def create_typedef_type(name, base_type, cname, is_external=0):
if base_type.is_complex:
if is_external:
raise ValueError("Complex external typedefs not supported")
return base_type
else:
return CTypedefType(name, base_type, cname, is_external)
class CTypedefType(BaseType):
#
# Pseudo-type defined with a ctypedef statement in a
# 'cdef extern from' block. Delegates most attribute
# lookups to the base type. ANYTHING NOT DEFINED
# HERE IS DELEGATED!
#
# qualified_name string
# typedef_name string
# typedef_cname string
# typedef_base_type PyrexType
# typedef_is_external bool
is_typedef = 1
typedef_is_external = 0
to_py_utility_code = None
from_py_utility_code = None
def __init__(self, name, base_type, cname, is_external=0):
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
def resolve(self):
return self.typedef_base_type.resolve()
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex or for_display:
base_code = self.typedef_name
else:
base_code = public_decl(self.typedef_cname, dll_linkage)
return self.base_declaration_code(base_code, entity_code)
def as_argument_type(self):
return self
def cast_code(self, expr_code):
# If self is really an array (rather than pointer), we can't cast.
# For example, the gmp mpz_t.
if self.typedef_base_type.is_array:
base_type = self.typedef_base_type.base_type
return CPtrType(base_type).cast_code(expr_code)
else:
return BaseType.cast_code(self, expr_code)
def __repr__(self):
return "" % self.typedef_cname
def __str__(self):
return self.typedef_name
def _create_utility_code(self, template_utility_code,
template_function_name):
type_name = self.typedef_cname.replace(" ","_").replace("::","__")
utility_code = template_utility_code.specialize(
type = self.typedef_cname,
TypeName = type_name)
function_name = template_function_name % type_name
return utility_code, function_name
def create_to_py_utility_code(self, env):
if self.typedef_is_external:
if not self.to_py_utility_code:
base_type = self.typedef_base_type
if type(base_type) is CIntType:
# Various subclasses have special methods
# that should be inherited.
self.to_py_utility_code, self.to_py_function = \
self._create_utility_code(c_typedef_int_to_py_function,
'__Pyx_PyInt_to_py_%s')
elif base_type.is_float:
pass # XXX implement!
elif base_type.is_complex:
pass # XXX implement!
pass
if self.to_py_utility_code:
env.use_utility_code(self.to_py_utility_code)
return True
# delegation
return self.typedef_base_type.create_to_py_utility_code(env)
def create_from_py_utility_code(self, env):
if self.typedef_is_external:
if not self.from_py_utility_code:
base_type = self.typedef_base_type
if type(base_type) is CIntType:
# Various subclasses have special methods
# that should be inherited.
self.from_py_utility_code, self.from_py_function = \
self._create_utility_code(c_typedef_int_from_py_function,
'__Pyx_PyInt_from_py_%s')
elif base_type.is_float:
pass # XXX implement!
elif base_type.is_complex:
pass # XXX implement!
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 error_condition(self, result_code):
if self.typedef_is_external:
if self.exception_value:
condition = "(%s == (%s)%s)" % (
result_code, self.typedef_cname, self.exception_value)
if self.exception_check:
condition += " && PyErr_Occurred()"
return condition
# delegation
return self.typedef_base_type.error_condition(result_code)
def __getattr__(self, name):
return getattr(self.typedef_base_type, name)
class BufferType(BaseType):
#
# Delegates most attribute
# lookups to the base type. ANYTHING NOT DEFINED
# HERE IS DELEGATED!
# dtype PyrexType
# ndim int
# mode str
# negative_indices bool
# cast bool
# is_buffer bool
# writable bool
is_buffer = 1
writable = True
def __init__(self, base, dtype, ndim, mode, negative_indices, cast):
self.base = base
self.dtype = dtype
self.ndim = ndim
self.buffer_ptr_type = CPtrType(dtype)
self.mode = mode
self.negative_indices = negative_indices
self.cast = cast
def as_argument_type(self):
return self
def __getattr__(self, name):
return getattr(self.base, name)
def __repr__(self):
return "" % self.base
class PyObjectType(PyrexType):
#
# Base class for all Python object types (reference-counted).
#
# buffer_defaults dict or None Default options for bu
name = "object"
is_pyobject = 1
default_value = "0"
buffer_defaults = None
is_extern = False
is_subclassed = False
def __str__(self):
return "Python object"
def __repr__(self):
return ""
def can_coerce_to_pyobject(self, env):
return True
def assignable_from(self, src_type):
# except for pointers, conversion will be attempted
return not src_type.is_ptr or src_type.is_string
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex or for_display:
base_code = "object"
else:
base_code = public_decl("PyObject", dll_linkage)
entity_code = "*%s" % entity_code
return self.base_declaration_code(base_code, entity_code)
def as_pyobject(self, cname):
if (not self.is_complete()) or self.is_extension_type:
return "(PyObject *)" + cname
else:
return cname
class BuiltinObjectType(PyObjectType):
is_builtin_type = 1
has_attributes = 1
base_type = None
module_name = '__builtin__'
alternative_name = None # used for str/bytes duality
def __init__(self, name, cname):
self.name = name
if name == 'str':
self.alternative_name = 'bytes'
elif name == 'bytes':
self.alternative_name = 'str'
self.cname = cname
self.typeptr_cname = "&" + cname
def set_scope(self, scope):
self.scope = scope
if scope:
scope.parent_type = self
def __str__(self):
return "%s object" % self.name
def __repr__(self):
return "<%s>"% self.cname
def assignable_from(self, src_type):
if isinstance(src_type, BuiltinObjectType):
return src_type.name == self.name or (
src_type.name == self.alternative_name and
src_type.name is not None)
elif src_type.is_extension_type:
return (src_type.module_name == '__builtin__' and
src_type.name == self.name)
else:
return True
def typeobj_is_available(self):
return True
def attributes_known(self):
return True
def subtype_of(self, type):
return type.is_pyobject and self.assignable_from(type)
def type_check_function(self, exact=True):
type_name = self.name
if type_name == 'bool':
return 'PyBool_Check'
if type_name == 'str':
type_check = 'PyString_Check'
elif type_name == 'frozenset':
type_check = 'PyFrozenSet_Check'
else:
type_check = 'Py%s_Check' % type_name.capitalize()
if exact:
type_check += 'Exact'
return type_check
def isinstance_code(self, arg):
return '%s(%s)' % (self.type_check_function(exact=False), arg)
def type_test_code(self, arg, notnone=False):
type_check = self.type_check_function(exact=True)
check = 'likely(%s(%s))' % (type_check, arg)
if not notnone:
check = check + ('||((%s) == Py_None)' % arg)
error = '(PyErr_Format(PyExc_TypeError, "Expected %s, got %%.200s", Py_TYPE(%s)->tp_name), 0)' % (self.name, arg)
return check + '||' + error
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex or for_display:
base_code = self.name
else:
base_code = public_decl("PyObject", dll_linkage)
entity_code = "*%s" % entity_code
return self.base_declaration_code(base_code, entity_code)
class PyExtensionType(PyObjectType):
#
# A Python extension type.
#
# name string
# scope CClassScope Attribute namespace
# visibility string
# typedef_flag boolean
# base_type PyExtensionType or None
# module_name string or None Qualified name of defining module
# objstruct_cname string Name of PyObject struct
# objtypedef_cname string Name of PyObject struct typedef
# typeobj_cname string or None C code fragment referring to type object
# typeptr_cname string or None Name of pointer to external type object
# vtabslot_cname string Name of C method table member
# vtabstruct_cname string Name of C method table struct
# vtabptr_cname string Name of pointer to C method table
# vtable_cname string Name of C method table definition
is_extension_type = 1
has_attributes = 1
objtypedef_cname = None
def __init__(self, name, typedef_flag, base_type, is_external=0):
self.name = name
self.scope = None
self.typedef_flag = typedef_flag
if base_type is not None:
base_type.is_subclassed = True
self.base_type = base_type
self.module_name = None
self.objstruct_cname = None
self.typeobj_cname = None
self.typeptr_cname = None
self.vtabslot_cname = None
self.vtabstruct_cname = None
self.vtabptr_cname = None
self.vtable_cname = None
self.is_external = is_external
def set_scope(self, scope):
self.scope = scope
if scope:
scope.parent_type = self
def subtype_of_resolved_type(self, other_type):
if other_type.is_extension_type:
return self is other_type or (
self.base_type and self.base_type.subtype_of(other_type))
else:
return other_type is py_object_type
def typeobj_is_available(self):
# Do we have a pointer to the type object?
return self.typeptr_cname
def typeobj_is_imported(self):
# If we don't know the C name of the type object but we do
# know which module it's defined in, it will be imported.
return self.typeobj_cname is None and self.module_name is not None
def assignable_from(self, src_type):
if self == src_type:
return True
if isinstance(src_type, PyExtensionType):
if src_type.base_type is not None:
return self.assignable_from(src_type.base_type)
return False
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0, deref = 0):
if pyrex or for_display:
base_code = self.name
else:
if self.typedef_flag:
objstruct = self.objstruct_cname
else:
objstruct = "struct %s" % self.objstruct_cname
base_code = public_decl(objstruct, dll_linkage)
if deref:
assert not entity_code
else:
entity_code = "*%s" % entity_code
return self.base_declaration_code(base_code, entity_code)
def type_test_code(self, py_arg, notnone=False):
none_check = "((%s) == Py_None)" % py_arg
type_check = "likely(__Pyx_TypeTest(%s, %s))" % (
py_arg, self.typeptr_cname)
if notnone:
return type_check
else:
return "likely(%s || %s)" % (none_check, type_check)
def attributes_known(self):
return self.scope is not None
def __str__(self):
return self.name
def __repr__(self):
return "" % (self.scope.class_name,
("", " typedef")[self.typedef_flag])
class CType(PyrexType):
#
# Base class for all C types (non-reference-counted).
#
# to_py_function string C function for converting to Python object
# from_py_function string C function for constructing from Python object
#
to_py_function = None
from_py_function = None
exception_value = None
exception_check = 1
def create_to_py_utility_code(self, env):
return self.to_py_function is not None
def create_from_py_utility_code(self, env):
return self.from_py_function is not None
def can_coerce_to_pyobject(self, env):
return self.create_to_py_utility_code(env)
def error_condition(self, result_code):
conds = []
if self.is_string:
conds.append("(!%s)" % result_code)
elif self.exception_value is not None:
conds.append("(%s == (%s)%s)" % (result_code, self.sign_and_name(), self.exception_value))
if self.exception_check:
conds.append("PyErr_Occurred()")
if len(conds) > 0:
return " && ".join(conds)
else:
return 0
class CVoidType(CType):
#
# C "void" type
#
is_void = 1
def __repr__(self):
return ""
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex or for_display:
base_code = "void"
else:
base_code = public_decl("void", dll_linkage)
return self.base_declaration_code(base_code, entity_code)
def is_complete(self):
return 0
class CNumericType(CType):
#
# Base class for all C numeric types.
#
# rank integer Relative size
# signed integer 0 = unsigned, 1 = unspecified, 2 = explicitly signed
#
is_numeric = 1
default_value = "0"
sign_words = ("unsigned ", "", "signed ")
def __init__(self, rank, signed = 1):
self.rank = rank
self.signed = signed
def sign_and_name(self):
s = self.sign_words[self.signed]
n = rank_to_type_name[self.rank]
return s + n
def __repr__(self):
return "" % self.sign_and_name()
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
type_name = self.sign_and_name()
if pyrex or for_display:
base_code = type_name.replace('PY_LONG_LONG', 'long long')
else:
base_code = public_decl(type_name, dll_linkage)
return self.base_declaration_code(base_code, entity_code)
type_conversion_predeclarations = ""
type_conversion_functions = ""
c_int_from_py_function = UtilityCode(
proto="""
static CYTHON_INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject *);
""",
impl="""
static CYTHON_INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject* x) {
const %(type)s neg_one = (%(type)s)-1, const_zero = 0;
const int is_unsigned = neg_one > const_zero;
if (sizeof(%(type)s) < sizeof(long)) {
long val = __Pyx_PyInt_AsLong(x);
if (unlikely(val != (long)(%(type)s)val)) {
if (!unlikely(val == -1 && PyErr_Occurred())) {
PyErr_SetString(PyExc_OverflowError,
(is_unsigned && unlikely(val < 0)) ?
"can't convert negative value to %(type)s" :
"value too large to convert to %(type)s");
}
return (%(type)s)-1;
}
return (%(type)s)val;
}
return (%(type)s)__Pyx_PyInt_As%(SignWord)sLong(x);
}
""") #fool emacs: '
c_long_from_py_function = UtilityCode(
proto="""
static CYTHON_INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject *);
""",
impl="""
static CYTHON_INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject* x) {
const %(type)s neg_one = (%(type)s)-1, const_zero = 0;
const int is_unsigned = neg_one > const_zero;
#if PY_VERSION_HEX < 0x03000000
if (likely(PyInt_Check(x))) {
long val = PyInt_AS_LONG(x);
if (is_unsigned && unlikely(val < 0)) {
PyErr_SetString(PyExc_OverflowError,
"can't convert negative value to %(type)s");
return (%(type)s)-1;
}
return (%(type)s)val;
} else
#endif
if (likely(PyLong_Check(x))) {
if (is_unsigned) {
if (unlikely(Py_SIZE(x) < 0)) {
PyErr_SetString(PyExc_OverflowError,
"can't convert negative value to %(type)s");
return (%(type)s)-1;
}
return PyLong_AsUnsigned%(TypeName)s(x);
} else {
return PyLong_As%(TypeName)s(x);
}
} else {
%(type)s val;
PyObject *tmp = __Pyx_PyNumber_Int(x);
if (!tmp) return (%(type)s)-1;
val = __Pyx_PyInt_As%(SignWord)s%(TypeName)s(tmp);
Py_DECREF(tmp);
return val;
}
}
""")
c_typedef_int_from_py_function = UtilityCode(
proto="""
static CYTHON_INLINE %(type)s __Pyx_PyInt_from_py_%(TypeName)s(PyObject *);
""",
impl="""
static CYTHON_INLINE %(type)s __Pyx_PyInt_from_py_%(TypeName)s(PyObject* x) {
const %(type)s neg_one = (%(type)s)-1, const_zero = (%(type)s)0;
const int is_unsigned = const_zero < neg_one;
if (sizeof(%(type)s) == sizeof(char)) {
if (is_unsigned)
return (%(type)s)__Pyx_PyInt_AsUnsignedChar(x);
else
return (%(type)s)__Pyx_PyInt_AsSignedChar(x);
} else if (sizeof(%(type)s) == sizeof(short)) {
if (is_unsigned)
return (%(type)s)__Pyx_PyInt_AsUnsignedShort(x);
else
return (%(type)s)__Pyx_PyInt_AsSignedShort(x);
} else if (sizeof(%(type)s) == sizeof(int)) {
if (is_unsigned)
return (%(type)s)__Pyx_PyInt_AsUnsignedInt(x);
else
return (%(type)s)__Pyx_PyInt_AsSignedInt(x);
} else if (sizeof(%(type)s) == sizeof(long)) {
if (is_unsigned)
return (%(type)s)__Pyx_PyInt_AsUnsignedLong(x);
else
return (%(type)s)__Pyx_PyInt_AsSignedLong(x);
} else if (sizeof(%(type)s) == sizeof(PY_LONG_LONG)) {
if (is_unsigned)
return (%(type)s)__Pyx_PyInt_AsUnsignedLongLong(x);
else
return (%(type)s)__Pyx_PyInt_AsSignedLongLong(x);
} else {
%(type)s val;
PyObject *v = __Pyx_PyNumber_Int(x);
#if PY_VERSION_HEX < 0x03000000
if (likely(v) && !PyLong_Check(v)) {
PyObject *tmp = v;
v = PyNumber_Long(tmp);
Py_DECREF(tmp);
}
#endif
if (likely(v)) {
int one = 1; int is_little = (int)*(unsigned char *)&one;
unsigned char *bytes = (unsigned char *)&val;
int ret = _PyLong_AsByteArray((PyLongObject *)v,
bytes, sizeof(val),
is_little, !is_unsigned);
Py_DECREF(v);
if (likely(!ret))
return val;
}
return (%(type)s)-1;
}
}
""")
c_typedef_int_to_py_function = UtilityCode(
proto="""
static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_%(TypeName)s(%(type)s);
""",
impl="""
static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_%(TypeName)s(%(type)s val) {
const %(type)s neg_one = (%(type)s)-1, const_zero = (%(type)s)0;
const int is_unsigned = const_zero < neg_one;
if ((sizeof(%(type)s) == sizeof(char)) ||
(sizeof(%(type)s) == sizeof(short))) {
return PyInt_FromLong((long)val);
} else if ((sizeof(%(type)s) == sizeof(int)) ||
(sizeof(%(type)s) == sizeof(long))) {
if (is_unsigned)
return PyLong_FromUnsignedLong((unsigned long)val);
else
return PyInt_FromLong((long)val);
} else if (sizeof(%(type)s) == sizeof(PY_LONG_LONG)) {
if (is_unsigned)
return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)val);
else
return PyLong_FromLongLong((PY_LONG_LONG)val);
} else {
int one = 1; int little = (int)*(unsigned char *)&one;
unsigned char *bytes = (unsigned char *)&val;
return _PyLong_FromByteArray(bytes, sizeof(%(type)s),
little, !is_unsigned);
}
}
""")
class CIntType(CNumericType):
is_int = 1
typedef_flag = 0
to_py_function = None
from_py_function = None
exception_value = -1
def __init__(self, rank, signed = 1):
CNumericType.__init__(self, rank, signed)
if self.to_py_function is None:
self.to_py_function = self.get_to_py_type_conversion()
if self.from_py_function is None:
self.from_py_function = self.get_from_py_type_conversion()
def get_to_py_type_conversion(self):
if self.rank < list(rank_to_type_name).index('int'):
# This assumes sizeof(short) < sizeof(int)
return "PyInt_FromLong"
else:
# Py{Int|Long}_From[Unsigned]Long[Long]
Prefix = "Int"
SignWord = ""
TypeName = "Long"
if not self.signed:
Prefix = "Long"
SignWord = "Unsigned"
if self.rank >= list(rank_to_type_name).index('PY_LONG_LONG'):
Prefix = "Long"
TypeName = "LongLong"
return "Py%s_From%s%s" % (Prefix, SignWord, TypeName)
def get_from_py_type_conversion(self):
type_name = rank_to_type_name[self.rank]
type_name = type_name.replace("PY_LONG_LONG", "long long")
TypeName = type_name.title().replace(" ", "")
SignWord = self.sign_words[self.signed].strip().title()
if self.rank >= list(rank_to_type_name).index('long'):
utility_code = c_long_from_py_function
else:
utility_code = c_int_from_py_function
utility_code.specialize(self,
SignWord=SignWord,
TypeName=TypeName)
func_name = "__Pyx_PyInt_As%s%s" % (SignWord, TypeName)
return func_name
def assignable_from_resolved_type(self, src_type):
return src_type.is_int or src_type.is_enum or src_type is error_type
class CAnonEnumType(CIntType):
is_enum = 1
def sign_and_name(self):
return 'int'
class CReturnCodeType(CIntType):
is_returncode = 1
class CBIntType(CIntType):
to_py_function = "__Pyx_PyBool_FromLong"
from_py_function = "__Pyx_PyObject_IsTrue"
exception_check = 1 # for C++ bool
def __repr__(self):
return ""
class CPyUnicodeIntType(CIntType):
# Py_UNICODE
# Py_UNICODE coerces from and to single character unicode strings,
# but we also allow Python integers as input. The value range for
# Py_UNICODE is 0..1114111, which is checked when converting from
# an integer value.
to_py_function = "PyUnicode_FromOrdinal"
from_py_function = "__Pyx_PyObject_AsPy_UNICODE"
def create_from_py_utility_code(self, env):
env.use_utility_code(pyobject_as_py_unicode_utility_code)
return True
def sign_and_name(self):
return "Py_UNICODE"
pyobject_as_py_unicode_utility_code = UtilityCode(
proto='''
static CYTHON_INLINE Py_UNICODE __Pyx_PyObject_AsPy_UNICODE(PyObject*);
''',
impl='''
static CYTHON_INLINE Py_UNICODE __Pyx_PyObject_AsPy_UNICODE(PyObject* x) {
static long maxval = 0;
long ival;
if (PyUnicode_Check(x)) {
if (unlikely(PyUnicode_GET_SIZE(x) != 1)) {
PyErr_Format(PyExc_ValueError,
"only single character unicode strings can be converted to Py_UNICODE, got length "
#if PY_VERSION_HEX < 0x02050000
"%d",
#else
"%zd",
#endif
PyUnicode_GET_SIZE(x));
return (Py_UNICODE)-1;
}
return PyUnicode_AS_UNICODE(x)[0];
}
if (unlikely(!maxval))
maxval = (long)PyUnicode_GetMax();
ival = __Pyx_PyInt_AsLong(x);
if (unlikely(ival < 0)) {
if (!PyErr_Occurred())
PyErr_SetString(PyExc_OverflowError,
"cannot convert negative value to Py_UNICODE");
return (Py_UNICODE)-1;
} else if (unlikely(ival > maxval)) {
PyErr_SetString(PyExc_OverflowError,
"value too large to convert to Py_UNICODE");
return (Py_UNICODE)-1;
}
return (Py_UNICODE)ival;
}
''')
class CPySSizeTType(CIntType):
to_py_function = "PyInt_FromSsize_t"
from_py_function = "__Pyx_PyIndex_AsSsize_t"
def sign_and_name(self):
return "Py_ssize_t"
class CSSizeTType(CIntType):
to_py_function = "PyInt_FromSsize_t"
from_py_function = "PyInt_AsSsize_t"
def sign_and_name(self):
return "Py_ssize_t"
class CSizeTType(CIntType):
to_py_function = "__Pyx_PyInt_FromSize_t"
from_py_function = "__Pyx_PyInt_AsSize_t"
def sign_and_name(self):
return "size_t"
class CFloatType(CNumericType):
is_float = 1
to_py_function = "PyFloat_FromDouble"
from_py_function = "__pyx_PyFloat_AsDouble"
exception_value = -1
def __init__(self, rank, math_h_modifier = ''):
CNumericType.__init__(self, rank, 1)
self.math_h_modifier = math_h_modifier
def assignable_from_resolved_type(self, src_type):
return (src_type.is_numeric and not src_type.is_complex) or src_type is error_type
class CComplexType(CNumericType):
is_complex = 1
to_py_function = "__pyx_PyComplex_FromComplex"
has_attributes = 1
scope = None
def __init__(self, real_type):
while real_type.is_typedef and not real_type.typedef_is_external:
real_type = real_type.typedef_base_type
if real_type.is_typedef and real_type.typedef_is_external:
# The below is not actually used: Coercions are currently disabled
# so that complex types of external types can not be created
self.funcsuffix = "_%s" % real_type.specialization_name()
elif hasattr(real_type, 'math_h_modifier'):
self.funcsuffix = real_type.math_h_modifier
else:
self.funcsuffix = "_%s" % real_type.specialization_name()
self.real_type = real_type
CNumericType.__init__(self, real_type.rank + 0.5, real_type.signed)
self.binops = {}
self.from_parts = "%s_from_parts" % self.specialization_name()
self.default_value = "%s(0, 0)" % self.from_parts
def __eq__(self, other):
if isinstance(self, CComplexType) and isinstance(other, CComplexType):
return self.real_type == other.real_type
else:
return False
def __ne__(self, other):
if isinstance(self, CComplexType) and isinstance(other, CComplexType):
return self.real_type != other.real_type
else:
return True
def __lt__(self, other):
if isinstance(self, CComplexType) and isinstance(other, CComplexType):
return self.real_type < other.real_type
else:
# this is arbitrary, but it makes sure we always have
# *some* kind of order
return False
def __hash__(self):
return ~hash(self.real_type)
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex or for_display:
real_code = self.real_type.declaration_code("", for_display, dll_linkage, pyrex)
base_code = "%s complex" % real_code
else:
base_code = public_decl(self.sign_and_name(), dll_linkage)
return self.base_declaration_code(base_code, entity_code)
def sign_and_name(self):
real_type_name = self.real_type.specialization_name()
real_type_name = real_type_name.replace('long__double','long_double')
real_type_name = real_type_name.replace('PY_LONG_LONG','long_long')
return Naming.type_prefix + real_type_name + "_complex"
def assignable_from(self, src_type):
# Temporary hack/feature disabling, see #441
if (not src_type.is_complex and src_type.is_numeric and src_type.is_typedef
and src_type.typedef_is_external):
return False
else:
return super(CComplexType, self).assignable_from(src_type)
def assignable_from_resolved_type(self, src_type):
return (src_type.is_complex and self.real_type.assignable_from_resolved_type(src_type.real_type)
or src_type.is_numeric and self.real_type.assignable_from_resolved_type(src_type)
or src_type is error_type)
def attributes_known(self):
if self.scope is None:
import Symtab
self.scope = scope = Symtab.CClassScope(
'',
None,
visibility="extern")
scope.parent_type = self
scope.declare_var("real", self.real_type, None, "real", is_cdef=True)
scope.declare_var("imag", self.real_type, None, "imag", is_cdef=True)
entry = scope.declare_cfunction(
"conjugate",
CFuncType(self, [CFuncTypeArg("self", self, None)]),
pos=None,
defining=1,
cname="__Pyx_c_conj%s" % self.funcsuffix)
return True
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(complex_header_utility_code)
env.use_utility_code(complex_real_imag_utility_code)
for utility_code in (complex_type_utility_code,
complex_from_parts_utility_code,
complex_arithmetic_utility_code):
env.use_utility_code(
utility_code.specialize(
self,
real_type = self.real_type.declaration_code(''),
m = self.funcsuffix))
return True
def create_to_py_utility_code(self, env):
env.use_utility_code(complex_real_imag_utility_code)
env.use_utility_code(complex_to_py_utility_code)
return True
def create_from_py_utility_code(self, env):
self.real_type.create_from_py_utility_code(env)
for utility_code in (complex_from_parts_utility_code,
complex_from_py_utility_code):
env.use_utility_code(
utility_code.specialize(
self,
real_type = self.real_type.declaration_code(''),
m = self.funcsuffix))
self.from_py_function = "__Pyx_PyComplex_As_" + self.specialization_name()
return True
def lookup_op(self, nargs, op):
try:
return self.binops[nargs, op]
except KeyError:
pass
try:
op_name = complex_ops[nargs, op]
self.binops[nargs, op] = func_name = "__Pyx_c_%s%s" % (op_name, self.funcsuffix)
return func_name
except KeyError:
return None
def unary_op(self, op):
return self.lookup_op(1, op)
def binary_op(self, op):
return self.lookup_op(2, op)
complex_ops = {
(1, '-'): 'neg',
(1, 'zero'): 'is_zero',
(2, '+'): 'sum',
(2, '-'): 'diff',
(2, '*'): 'prod',
(2, '/'): 'quot',
(2, '=='): 'eq',
}
complex_header_utility_code = UtilityCode(
proto_block='h_code',
proto="""
#if !defined(CYTHON_CCOMPLEX)
#if defined(__cplusplus)
#define CYTHON_CCOMPLEX 1
#elif defined(_Complex_I)
#define CYTHON_CCOMPLEX 1
#else
#define CYTHON_CCOMPLEX 0
#endif
#endif
#if CYTHON_CCOMPLEX
#ifdef __cplusplus
#include
#else
#include
#endif
#endif
#if CYTHON_CCOMPLEX && !defined(__cplusplus) && defined(__sun__) && defined(__GNUC__)
#undef _Complex_I
#define _Complex_I 1.0fj
#endif
""")
complex_real_imag_utility_code = UtilityCode(
proto="""
#if CYTHON_CCOMPLEX
#ifdef __cplusplus
#define __Pyx_CREAL(z) ((z).real())
#define __Pyx_CIMAG(z) ((z).imag())
#else
#define __Pyx_CREAL(z) (__real__(z))
#define __Pyx_CIMAG(z) (__imag__(z))
#endif
#else
#define __Pyx_CREAL(z) ((z).real)
#define __Pyx_CIMAG(z) ((z).imag)
#endif
#if defined(_WIN32) && defined(__cplusplus) && CYTHON_CCOMPLEX
#define __Pyx_SET_CREAL(z,x) ((z).real(x))
#define __Pyx_SET_CIMAG(z,y) ((z).imag(y))
#else
#define __Pyx_SET_CREAL(z,x) __Pyx_CREAL(z) = (x)
#define __Pyx_SET_CIMAG(z,y) __Pyx_CIMAG(z) = (y)
#endif
""")
complex_type_utility_code = UtilityCode(
proto_block='complex_type_declarations',
proto="""
#if CYTHON_CCOMPLEX
#ifdef __cplusplus
typedef ::std::complex< %(real_type)s > %(type_name)s;
#else
typedef %(real_type)s _Complex %(type_name)s;
#endif
#else
typedef struct { %(real_type)s real, imag; } %(type_name)s;
#endif
""")
complex_from_parts_utility_code = UtilityCode(
proto_block='utility_code_proto',
proto="""
static CYTHON_INLINE %(type)s %(type_name)s_from_parts(%(real_type)s, %(real_type)s);
""",
impl="""
#if CYTHON_CCOMPLEX
#ifdef __cplusplus
static CYTHON_INLINE %(type)s %(type_name)s_from_parts(%(real_type)s x, %(real_type)s y) {
return ::std::complex< %(real_type)s >(x, y);
}
#else
static CYTHON_INLINE %(type)s %(type_name)s_from_parts(%(real_type)s x, %(real_type)s y) {
return x + y*(%(type)s)_Complex_I;
}
#endif
#else
static CYTHON_INLINE %(type)s %(type_name)s_from_parts(%(real_type)s x, %(real_type)s y) {
%(type)s z;
z.real = x;
z.imag = y;
return z;
}
#endif
""")
complex_to_py_utility_code = UtilityCode(
proto="""
#define __pyx_PyComplex_FromComplex(z) \\
PyComplex_FromDoubles((double)__Pyx_CREAL(z), \\
(double)__Pyx_CIMAG(z))
""")
complex_from_py_utility_code = UtilityCode(
proto="""
static %(type)s __Pyx_PyComplex_As_%(type_name)s(PyObject*);
""",
impl="""
static %(type)s __Pyx_PyComplex_As_%(type_name)s(PyObject* o) {
Py_complex cval;
if (PyComplex_CheckExact(o))
cval = ((PyComplexObject *)o)->cval;
else
cval = PyComplex_AsCComplex(o);
return %(type_name)s_from_parts(
(%(real_type)s)cval.real,
(%(real_type)s)cval.imag);
}
""")
complex_arithmetic_utility_code = UtilityCode(
proto="""
#if CYTHON_CCOMPLEX
#define __Pyx_c_eq%(m)s(a, b) ((a)==(b))
#define __Pyx_c_sum%(m)s(a, b) ((a)+(b))
#define __Pyx_c_diff%(m)s(a, b) ((a)-(b))
#define __Pyx_c_prod%(m)s(a, b) ((a)*(b))
#define __Pyx_c_quot%(m)s(a, b) ((a)/(b))
#define __Pyx_c_neg%(m)s(a) (-(a))
#ifdef __cplusplus
#define __Pyx_c_is_zero%(m)s(z) ((z)==(%(real_type)s)0)
#define __Pyx_c_conj%(m)s(z) (::std::conj(z))
/*#define __Pyx_c_abs%(m)s(z) (::std::abs(z))*/
#else
#define __Pyx_c_is_zero%(m)s(z) ((z)==0)
#define __Pyx_c_conj%(m)s(z) (conj%(m)s(z))
/*#define __Pyx_c_abs%(m)s(z) (cabs%(m)s(z))*/
#endif
#else
static CYTHON_INLINE int __Pyx_c_eq%(m)s(%(type)s, %(type)s);
static CYTHON_INLINE %(type)s __Pyx_c_sum%(m)s(%(type)s, %(type)s);
static CYTHON_INLINE %(type)s __Pyx_c_diff%(m)s(%(type)s, %(type)s);
static CYTHON_INLINE %(type)s __Pyx_c_prod%(m)s(%(type)s, %(type)s);
static CYTHON_INLINE %(type)s __Pyx_c_quot%(m)s(%(type)s, %(type)s);
static CYTHON_INLINE %(type)s __Pyx_c_neg%(m)s(%(type)s);
static CYTHON_INLINE int __Pyx_c_is_zero%(m)s(%(type)s);
static CYTHON_INLINE %(type)s __Pyx_c_conj%(m)s(%(type)s);
/*static CYTHON_INLINE %(real_type)s __Pyx_c_abs%(m)s(%(type)s);*/
#endif
""",
impl="""
#if CYTHON_CCOMPLEX
#else
static CYTHON_INLINE int __Pyx_c_eq%(m)s(%(type)s a, %(type)s b) {
return (a.real == b.real) && (a.imag == b.imag);
}
static CYTHON_INLINE %(type)s __Pyx_c_sum%(m)s(%(type)s a, %(type)s b) {
%(type)s z;
z.real = a.real + b.real;
z.imag = a.imag + b.imag;
return z;
}
static CYTHON_INLINE %(type)s __Pyx_c_diff%(m)s(%(type)s a, %(type)s b) {
%(type)s z;
z.real = a.real - b.real;
z.imag = a.imag - b.imag;
return z;
}
static CYTHON_INLINE %(type)s __Pyx_c_prod%(m)s(%(type)s a, %(type)s b) {
%(type)s z;
z.real = a.real * b.real - a.imag * b.imag;
z.imag = a.real * b.imag + a.imag * b.real;
return z;
}
static CYTHON_INLINE %(type)s __Pyx_c_quot%(m)s(%(type)s a, %(type)s b) {
%(type)s z;
%(real_type)s denom = b.real * b.real + b.imag * b.imag;
z.real = (a.real * b.real + a.imag * b.imag) / denom;
z.imag = (a.imag * b.real - a.real * b.imag) / denom;
return z;
}
static CYTHON_INLINE %(type)s __Pyx_c_neg%(m)s(%(type)s a) {
%(type)s z;
z.real = -a.real;
z.imag = -a.imag;
return z;
}
static CYTHON_INLINE int __Pyx_c_is_zero%(m)s(%(type)s a) {
return (a.real == 0) && (a.imag == 0);
}
static CYTHON_INLINE %(type)s __Pyx_c_conj%(m)s(%(type)s a) {
%(type)s z;
z.real = a.real;
z.imag = -a.imag;
return z;
}
/*
static CYTHON_INLINE %(real_type)s __Pyx_c_abs%(m)s(%(type)s z) {
#if HAVE_HYPOT
return hypot%(m)s(z.real, z.imag);
#else
return sqrt%(m)s(z.real*z.real + z.imag*z.imag);
#endif
}
*/
#endif
""")
class CArrayType(CType):
# base_type CType Element type
# size integer or None Number of elements
is_array = 1
def __init__(self, base_type, size):
self.base_type = base_type
self.size = size
if base_type is c_char_type:
self.is_string = 1
def __repr__(self):
return "" % (self.size, repr(self.base_type))
def same_as_resolved_type(self, other_type):
return ((other_type.is_array and
self.base_type.same_as(other_type.base_type))
or other_type is error_type)
def assignable_from_resolved_type(self, src_type):
# Can't assign to a variable of an array type
return 0
def element_ptr_type(self):
return c_ptr_type(self.base_type)
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if self.size is not None:
dimension_code = self.size
else:
dimension_code = ""
if entity_code.startswith("*"):
entity_code = "(%s)" % entity_code
return self.base_type.declaration_code(
"%s[%s]" % (entity_code, dimension_code),
for_display, dll_linkage, pyrex)
def as_argument_type(self):
return c_ptr_type(self.base_type)
def is_complete(self):
return self.size is not None
class CPtrType(CType):
# base_type CType Referenced type
is_ptr = 1
default_value = "0"
def __init__(self, base_type):
self.base_type = base_type
def __repr__(self):
return "" % repr(self.base_type)
def same_as_resolved_type(self, other_type):
return ((other_type.is_ptr and
self.base_type.same_as(other_type.base_type))
or other_type is error_type)
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
#print "CPtrType.declaration_code: pointer to", self.base_type ###
return self.base_type.declaration_code(
"*%s" % entity_code,
for_display, dll_linkage, pyrex)
def assignable_from_resolved_type(self, other_type):
if other_type is error_type:
return 1
if other_type.is_null_ptr:
return 1
if self.base_type.is_cfunction:
if other_type.is_ptr:
other_type = other_type.base_type.resolve()
if other_type.is_cfunction:
return self.base_type.pointer_assignable_from_resolved_type(other_type)
else:
return 0
if (self.base_type.is_cpp_class and other_type.is_ptr
and other_type.base_type.is_cpp_class and other_type.base_type.is_subclass(self.base_type)):
return 1
if other_type.is_array or other_type.is_ptr:
return self.base_type.is_void or self.base_type.same_as(other_type.base_type)
return 0
def specialize(self, values):
base_type = self.base_type.specialize(values)
if base_type == self.base_type:
return self
else:
return CPtrType(base_type)
class CNullPtrType(CPtrType):
is_null_ptr = 1
class CReferenceType(BaseType):
is_reference = 1
def __init__(self, base_type):
self.ref_base_type = base_type
def __repr__(self):
return "" % repr(self.ref_base_type)
def __str__(self):
return "%s &" % self.ref_base_type
def as_argument_type(self):
return self
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
#print "CReferenceType.declaration_code: pointer to", self.base_type ###
return self.ref_base_type.declaration_code(
"&%s" % entity_code,
for_display, dll_linkage, pyrex)
def specialize(self, values):
base_type = self.ref_base_type.specialize(values)
if base_type == self.ref_base_type:
return self
else:
return CReferenceType(base_type)
def __getattr__(self, name):
return getattr(self.ref_base_type, name)
class CFuncType(CType):
# return_type CType
# args [CFuncTypeArg]
# has_varargs boolean
# exception_value string
# exception_check boolean True if PyErr_Occurred check needed
# calling_convention string Function calling convention
# nogil boolean Can be called without gil
# with_gil boolean Acquire gil around function body
# templates [string] or None
is_cfunction = 1
original_sig = None
def __init__(self, return_type, args, has_varargs = 0,
exception_value = None, exception_check = 0, calling_convention = "",
nogil = 0, with_gil = 0, is_overridable = 0, optional_arg_count = 0,
templates = None):
self.return_type = return_type
self.args = args
self.has_varargs = has_varargs
self.optional_arg_count = optional_arg_count
self.exception_value = exception_value
self.exception_check = exception_check
self.calling_convention = calling_convention
self.nogil = nogil
self.with_gil = with_gil
self.is_overridable = is_overridable
self.templates = templates
def __repr__(self):
arg_reprs = map(repr, self.args)
if self.has_varargs:
arg_reprs.append("...")
if self.exception_value:
except_clause = " %r" % self.exception_value
else:
except_clause = ""
if self.exception_check:
except_clause += "?"
return "" % (
repr(self.return_type),
self.calling_convention_prefix(),
",".join(arg_reprs),
except_clause)
def calling_convention_prefix(self):
cc = self.calling_convention
if cc:
return cc + " "
else:
return ""
def same_c_signature_as(self, other_type, as_cmethod = 0):
return self.same_c_signature_as_resolved_type(
other_type.resolve(), as_cmethod)
def same_c_signature_as_resolved_type(self, other_type, as_cmethod = 0):
#print "CFuncType.same_c_signature_as_resolved_type:", \
# self, other_type, "as_cmethod =", as_cmethod ###
if other_type is error_type:
return 1
if not other_type.is_cfunction:
return 0
if self.is_overridable != other_type.is_overridable:
return 0
nargs = len(self.args)
if nargs != len(other_type.args):
return 0
# When comparing C method signatures, the first argument
# 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 self.has_varargs != other_type.has_varargs:
return 0
if self.optional_arg_count != other_type.optional_arg_count:
return 0
if not self.return_type.same_as(other_type.return_type):
return 0
if not self.same_calling_convention_as(other_type):
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)
def compatible_signature_with_resolved_type(self, other_type, as_cmethod):
#print "CFuncType.same_c_signature_as_resolved_type:", \
# self, other_type, "as_cmethod =", as_cmethod ###
if other_type is error_type:
return 1
if not other_type.is_cfunction:
return 0
if not self.is_overridable and other_type.is_overridable:
return 0
nargs = len(self.args)
if nargs - self.optional_arg_count != len(other_type.args) - other_type.optional_arg_count:
return 0
if self.optional_arg_count < other_type.optional_arg_count:
return 0
# When comparing C method signatures, the first argument
# is exempt from compatibility checking (the proper check
# is performed elsewhere).
for i in range(as_cmethod, len(other_type.args)):
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 not self.return_type.subtype_of_resolved_type(other_type.return_type):
return 0
if not self.same_calling_convention_as(other_type):
return 0
if self.nogil != other_type.nogil:
return 0
self.original_sig = other_type.original_sig or other_type
if as_cmethod:
self.args[0] = other_type.args[0]
return 1
def narrower_c_signature_than(self, other_type, as_cmethod = 0):
return self.narrower_c_signature_than_resolved_type(other_type.resolve(), as_cmethod)
def narrower_c_signature_than_resolved_type(self, other_type, as_cmethod):
if other_type is error_type:
return 1
if not other_type.is_cfunction:
return 0
nargs = len(self.args)
if nargs != len(other_type.args):
return 0
for i in range(as_cmethod, nargs):
if not self.args[i].type.subtype_of_resolved_type(other_type.args[i].type):
return 0
else:
self.args[i].needs_type_test = other_type.args[i].needs_type_test \
or not self.args[i].type.same_as(other_type.args[i].type)
if self.has_varargs != other_type.has_varargs:
return 0
if self.optional_arg_count != other_type.optional_arg_count:
return 0
if not self.return_type.subtype_of_resolved_type(other_type.return_type):
return 0
return 1
def same_calling_convention_as(self, other):
## XXX Under discussion ...
## callspec_words = ("__stdcall", "__cdecl", "__fastcall")
## cs1 = self.calling_convention
## cs2 = other.calling_convention
## if (cs1 in callspec_words or
## cs2 in callspec_words):
## return cs1 == cs2
## else:
## return True
sc1 = self.calling_convention == '__stdcall'
sc2 = other.calling_convention == '__stdcall'
return sc1 == sc2
def same_exception_signature_as(self, other_type):
return self.same_exception_signature_as_resolved_type(
other_type.resolve())
def same_exception_signature_as_resolved_type(self, other_type):
return self.exception_value == other_type.exception_value \
and self.exception_check == other_type.exception_check
def same_as_resolved_type(self, other_type, as_cmethod = 0):
return self.same_c_signature_as_resolved_type(other_type, as_cmethod) \
and self.same_exception_signature_as_resolved_type(other_type) \
and self.nogil == other_type.nogil
def pointer_assignable_from_resolved_type(self, other_type):
return self.same_c_signature_as_resolved_type(other_type) \
and self.same_exception_signature_as_resolved_type(other_type) \
and not (self.nogil and not other_type.nogil)
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0,
with_calling_convention = 1):
arg_decl_list = []
for arg in self.args[:len(self.args)-self.optional_arg_count]:
arg_decl_list.append(
arg.type.declaration_code("", for_display, pyrex = pyrex))
if self.is_overridable:
arg_decl_list.append("int %s" % Naming.skip_dispatch_cname)
if self.optional_arg_count:
arg_decl_list.append(self.op_arg_struct.declaration_code(Naming.optional_args_cname))
if self.has_varargs:
arg_decl_list.append("...")
arg_decl_code = ", ".join(arg_decl_list)
if not arg_decl_code and not pyrex:
arg_decl_code = "void"
trailer = ""
if (pyrex or for_display) and not self.return_type.is_pyobject:
if self.exception_value and self.exception_check:
trailer = " except? %s" % self.exception_value
elif self.exception_value:
trailer = " except %s" % self.exception_value
elif self.exception_check == '+':
trailer = " except +"
else:
" except *" # ignored
if self.nogil:
trailer += " nogil"
if not with_calling_convention:
cc = ''
else:
cc = self.calling_convention_prefix()
if (not entity_code and cc) or entity_code.startswith("*"):
entity_code = "(%s%s)" % (cc, entity_code)
cc = ""
return self.return_type.declaration_code(
"%s%s(%s)%s" % (cc, entity_code, arg_decl_code, trailer),
for_display, dll_linkage, pyrex)
def function_header_code(self, func_name, arg_code):
return "%s%s(%s)" % (self.calling_convention_prefix(),
func_name, arg_code)
def signature_string(self):
s = self.declaration_code("")
return s
def signature_cast_string(self):
s = self.declaration_code("(*)", with_calling_convention=False)
return '(%s)' % s
def specialize(self, values):
if self.templates is None:
new_templates = None
else:
new_templates = [v.specialize(values) for v in self.templates]
return CFuncType(self.return_type.specialize(values),
[arg.specialize(values) for arg in self.args],
has_varargs = 0,
exception_value = self.exception_value,
exception_check = self.exception_check,
calling_convention = self.calling_convention,
nogil = self.nogil,
with_gil = self.with_gil,
is_overridable = self.is_overridable,
optional_arg_count = self.optional_arg_count,
templates = new_templates)
def opt_arg_cname(self, arg_name):
return self.op_arg_struct.base_type.scope.lookup(arg_name).cname
class CFuncTypeArg(object):
# name string
# cname string
# type PyrexType
# pos source file position
# FIXME: is this the right setup? should None be allowed here?
not_none = False
or_none = False
accept_none = True
def __init__(self, name, type, pos, cname=None):
self.name = name
if cname is not None:
self.cname = cname
else:
self.cname = Naming.var_prefix + name
self.type = type
self.pos = pos
self.needs_type_test = False # TODO: should these defaults be set in analyse_types()?
def __repr__(self):
return "%s:%s" % (self.name, repr(self.type))
def declaration_code(self, for_display = 0):
return self.type.declaration_code(self.cname, for_display)
def specialize(self, values):
return CFuncTypeArg(self.name, self.type.specialize(values), self.pos, self.cname)
class StructUtilityCode(object):
def __init__(self, type, forward_decl):
self.type = type
self.header = "static PyObject* %s(%s)" % (type.to_py_function, type.declaration_code('s'))
self.forward_decl = forward_decl
def __eq__(self, other):
return isinstance(other, StructUtilityCode) and self.header == other.header
def __hash__(self):
return hash(self.header)
def put_code(self, output):
code = output['utility_code_def']
proto = output['utility_code_proto']
code.putln("%s {" % self.header)
code.putln("PyObject* res;")
code.putln("PyObject* member;")
code.putln("res = PyDict_New(); if (res == NULL) return NULL;")
for member in self.type.scope.var_entries:
nameconst_cname = code.get_py_string_const(member.name, identifier=True)
code.putln("member = %s(s.%s); if (member == NULL) goto bad;" % (
member.type.to_py_function, member.cname))
code.putln("if (PyDict_SetItem(res, %s, member) < 0) goto bad;" % nameconst_cname)
code.putln("Py_DECREF(member);")
code.putln("return res;")
code.putln("bad:")
code.putln("Py_XDECREF(member);")
code.putln("Py_DECREF(res);")
code.putln("return NULL;")
code.putln("}")
# 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.declaration_code('') + ';')
proto.putln(self.header + ";")
class CStructOrUnionType(CType):
# name string
# cname string
# kind string "struct" or "union"
# scope StructOrUnionScope, or None if incomplete
# typedef_flag boolean
# packed boolean
# entry Entry
is_struct_or_union = 1
has_attributes = 1
def __init__(self, name, kind, scope, typedef_flag, cname, packed=False):
self.name = name
self.cname = cname
self.kind = kind
self.scope = scope
self.typedef_flag = typedef_flag
self.is_struct = kind == 'struct'
if self.is_struct:
self.to_py_function = "%s_to_py_%s" % (Naming.convert_func_prefix, self.cname)
self.exception_check = True
self._convert_code = None
self.packed = packed
def create_to_py_utility_code(self, env):
if env.outer_scope is None:
return False
if self._convert_code is False: return # tri-state-ish
if self._convert_code is None:
for member in self.scope.var_entries:
if not member.type.to_py_function or not member.type.create_to_py_utility_code(env):
self.to_py_function = None
self._convert_code = False
return False
forward_decl = (self.entry.visibility != 'extern')
self._convert_code = StructUtilityCode(self, forward_decl)
env.use_utility_code(self._convert_code)
return True
def __repr__(self):
return "" % (self.name, self.cname,
("", " typedef")[self.typedef_flag])
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex or for_display:
base_code = self.name
else:
if self.typedef_flag:
base_code = self.cname
else:
base_code = "%s %s" % (self.kind, self.cname)
base_code = public_decl(base_code, dll_linkage)
return self.base_declaration_code(base_code, entity_code)
def __eq__(self, other):
try:
return (isinstance(other, CStructOrUnionType) and
self.name == other.name)
except AttributeError:
return False
def __lt__(self, other):
try:
return self.name < other.name
except AttributeError:
# this is arbitrary, but it makes sure we always have
# *some* kind of order
return False
def __hash__(self):
return hash(self.cname) ^ hash(self.kind)
def is_complete(self):
return self.scope is not None
def attributes_known(self):
return self.is_complete()
def can_be_complex(self):
# Does the struct consist of exactly two identical floats?
fields = self.scope.var_entries
if len(fields) != 2: return False
a, b = fields
return (a.type.is_float and b.type.is_float and
a.type.declaration_code("") ==
b.type.declaration_code(""))
def struct_nesting_depth(self):
child_depths = [x.type.struct_nesting_depth()
for x in self.scope.var_entries]
return max(child_depths) + 1
class CppClassType(CType):
# name string
# cname string
# scope CppClassScope
# templates [string] or None
is_cpp_class = 1
has_attributes = 1
exception_check = True
namespace = None
def __init__(self, name, scope, cname, base_classes, templates = None, template_type = None):
self.name = name
self.cname = cname
self.scope = scope
self.base_classes = base_classes
self.operators = []
self.templates = templates
self.template_type = template_type
self.specializations = {}
def specialize_here(self, pos, template_values = None):
if self.templates is None:
error(pos, "'%s' type is not a template" % self);
return PyrexTypes.error_type
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)))
return error_type
return self.specialize(dict(zip(self.templates, template_values)))
def specialize(self, values):
if not self.templates and not self.namespace:
return self
if self.templates is None:
self.templates = []
key = tuple(values.items())
if key in self.specializations:
return self.specializations[key]
template_values = [t.specialize(values) for t in self.templates]
specialized = self.specializations[key] = \
CppClassType(self.name, None, self.cname, [], template_values, template_type=self)
# Need to do these *after* self.specializations[key] is set
# to avoid infinite recursion on circular references.
specialized.base_classes = [b.specialize(values) for b in self.base_classes]
specialized.scope = self.scope.specialize(values)
if self.namespace is not None:
specialized.namespace = self.namespace.specialize(values)
return specialized
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if self.templates:
template_strings = [param.declaration_code('', for_display, None, pyrex)
for param in self.templates]
templates = "<%s>" % ",".join(template_strings)
if templates[-2:] == ">>":
templates = templates[:-2] + "> >"
else:
templates = ""
if pyrex or for_display:
base_code = "%s%s" % (self.name, templates)
else:
base_code = "%s%s" % (self.cname, templates)
if self.namespace is not None:
base_code = "%s::%s" % (self.namespace.declaration_code(''), base_code)
base_code = public_decl(base_code, dll_linkage)
return self.base_declaration_code(base_code, entity_code)
def is_subclass(self, other_type):
# TODO(danilo): Handle templates.
if self.same_as_resolved_type(other_type):
return 1
for base_class in self.base_classes:
if base_class.is_subclass(other_type):
return 1
return 0
def same_as_resolved_type(self, other_type):
if other_type.is_cpp_class:
if self == other_type:
return 1
elif self.template_type and self.template_type == other_type.template_type:
if self.templates == other_type.templates:
return 1
for t1, t2 in zip(self.templates, other_type.templates):
if not t1.same_as_resolved_type(t2):
return 0
return 1
return 0
def assignable_from_resolved_type(self, other_type):
# TODO: handle operator=(...) here?
if other_type is error_type:
return True
return other_type.is_cpp_class and other_type.is_subclass(self)
def attributes_known(self):
return self.scope is not None
class TemplatePlaceholderType(CType):
def __init__(self, name):
self.name = name
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if entity_code:
return self.name + " " + entity_code
else:
return self.name
def specialize(self, values):
if self in values:
return values[self]
else:
return self
def same_as_resolved_type(self, other_type):
if isinstance(other_type, TemplatePlaceholderType):
return self.name == other_type.name
else:
return 0
def __hash__(self):
return hash(self.name)
def __cmp__(self, other):
if isinstance(other, TemplatePlaceholderType):
return cmp(self.name, other.name)
else:
return cmp(type(self), type(other))
class CEnumType(CType):
# name string
# cname string or None
# typedef_flag boolean
is_enum = 1
signed = 1
rank = -1 # Ranks below any integer type
to_py_function = "PyInt_FromLong"
from_py_function = "PyInt_AsLong"
def __init__(self, name, cname, typedef_flag):
self.name = name
self.cname = cname
self.values = []
self.typedef_flag = typedef_flag
def __str__(self):
return self.name
def __repr__(self):
return "" % (self.name, self.cname,
("", " typedef")[self.typedef_flag])
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex or for_display:
base_code = self.name
else:
if 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)
class CStringType(object):
# Mixin class for C string types.
is_string = 1
is_unicode = 0
to_py_function = "PyBytes_FromString"
from_py_function = "PyBytes_AsString"
exception_value = "NULL"
def literal_code(self, value):
assert isinstance(value, str)
return '"%s"' % StringEncoding.escape_byte_string(value)
class CUTF8CharArrayType(CStringType, CArrayType):
# C 'char []' type.
is_unicode = 1
to_py_function = "PyUnicode_DecodeUTF8"
exception_value = "NULL"
def __init__(self, size):
CArrayType.__init__(self, c_char_type, size)
class CCharArrayType(CStringType, CArrayType):
# C 'char []' type.
def __init__(self, size):
CArrayType.__init__(self, c_char_type, size)
class CCharPtrType(CStringType, CPtrType):
# C 'char *' type.
def __init__(self):
CPtrType.__init__(self, c_char_type)
class CUCharPtrType(CStringType, CPtrType):
# C 'unsigned char *' type.
to_py_function = "__Pyx_PyBytes_FromUString"
from_py_function = "__Pyx_PyBytes_AsUString"
def __init__(self):
CPtrType.__init__(self, c_uchar_type)
class UnspecifiedType(PyrexType):
# Used as a placeholder until the type can be determined.
is_unspecified = 1
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
return ""
def same_as_resolved_type(self, other_type):
return False
class ErrorType(PyrexType):
# Used to prevent propagation of error messages.
is_error = 1
exception_value = "0"
exception_check = 0
to_py_function = "dummy"
from_py_function = "dummy"
def create_to_py_utility_code(self, env):
return True
def create_from_py_utility_code(self, env):
return True
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
return ""
def same_as_resolved_type(self, other_type):
return 1
def error_condition(self, result_code):
return "dummy"
rank_to_type_name = (
"char", # 0
"short", # 1
"int", # 2
"long", # 3
"PY_LONG_LONG", # 4
"float", # 5
"double", # 6
"long double", # 7
)
RANK_INT = list(rank_to_type_name).index('int')
RANK_LONG = list(rank_to_type_name).index('long')
UNSIGNED = 0
SIGNED = 2
py_object_type = PyObjectType()
c_void_type = CVoidType()
c_uchar_type = CIntType(0, UNSIGNED)
c_ushort_type = CIntType(1, UNSIGNED)
c_uint_type = CIntType(2, UNSIGNED)
c_ulong_type = CIntType(3, UNSIGNED)
c_ulonglong_type = CIntType(4, UNSIGNED)
c_char_type = CIntType(0)
c_short_type = CIntType(1)
c_int_type = CIntType(2)
c_long_type = CIntType(3)
c_longlong_type = CIntType(4)
c_schar_type = CIntType(0, SIGNED)
c_sshort_type = CIntType(1, SIGNED)
c_sint_type = CIntType(2, SIGNED)
c_slong_type = CIntType(3, SIGNED)
c_slonglong_type = CIntType(4, SIGNED)
c_float_type = CFloatType(5, math_h_modifier='f')
c_double_type = CFloatType(6)
c_longdouble_type = CFloatType(7, math_h_modifier='l')
c_float_complex_type = CComplexType(c_float_type)
c_double_complex_type = CComplexType(c_double_type)
c_longdouble_complex_type = CComplexType(c_longdouble_type)
c_anon_enum_type = CAnonEnumType(-1)
c_returncode_type = CReturnCodeType(RANK_INT)
c_bint_type = CBIntType(RANK_INT)
c_py_unicode_type = CPyUnicodeIntType(RANK_INT-0.5, UNSIGNED)
c_py_ssize_t_type = CPySSizeTType(RANK_LONG+0.5, SIGNED)
c_ssize_t_type = CSSizeTType(RANK_LONG+0.5, SIGNED)
c_size_t_type = CSizeTType(RANK_LONG+0.5, UNSIGNED)
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_array_type = CCharArrayType(None)
c_char_ptr_type = CCharPtrType()
c_uchar_ptr_type = CUCharPtrType()
c_utf8_char_array_type = CUTF8CharArrayType(None)
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_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)
# the Py_buffer type is defined in Builtin.py
c_py_buffer_type = CStructOrUnionType("Py_buffer", "struct", None, 1, "Py_buffer")
c_py_buffer_ptr_type = CPtrType(c_py_buffer_type)
error_type = ErrorType()
unspecified_type = UnspecifiedType()
modifiers_and_name_to_type = {
#(signed, longness, name) : type
(0, 0, "char"): c_uchar_type,
(1, 0, "char"): c_char_type,
(2, 0, "char"): c_schar_type,
(0, -1, "int"): c_ushort_type,
(0, 0, "int"): c_uint_type,
(0, 1, "int"): c_ulong_type,
(0, 2, "int"): c_ulonglong_type,
(1, -1, "int"): c_short_type,
(1, 0, "int"): c_int_type,
(1, 1, "int"): c_long_type,
(1, 2, "int"): c_longlong_type,
(2, -1, "int"): c_sshort_type,
(2, 0, "int"): c_sint_type,
(2, 1, "int"): c_slong_type,
(2, 2, "int"): c_slonglong_type,
(1, 0, "float"): c_float_type,
(1, 0, "double"): c_double_type,
(1, 1, "double"): c_longdouble_type,
(1, 0, "complex"): c_float_complex_type,
(1, 0, "floatcomplex"): c_float_complex_type,
(1, 0, "doublecomplex"): c_double_complex_type,
(1, 1, "doublecomplex"): c_longdouble_complex_type,
#
(1, 0, "void"): c_void_type,
(1, 0, "bint"): c_bint_type,
(0, 0, "Py_UNICODE"): c_py_unicode_type,
(2, 0, "Py_ssize_t"): c_py_ssize_t_type,
(2, 0, "ssize_t") : c_ssize_t_type,
(0, 0, "size_t") : c_size_t_type,
(1, 0, "object"): py_object_type,
}
def is_promotion(src_type, dst_type):
# It's hard to find a hard definition of promotion, but empirical
# evidence suggests that the below is all that's allowed.
if src_type.is_numeric:
if dst_type.same_as(c_int_type):
unsigned = (not src_type.signed)
return (src_type.is_enum or
(src_type.is_int and
unsigned + src_type.rank < dst_type.rank))
elif dst_type.same_as(c_double_type):
return src_type.is_float and src_type.rank <= dst_type.rank
return False
def best_match(args, functions, pos=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.
This function is used, e.g., when deciding which overloaded method
to dispatch for C++ classes.
We first eliminate functions based on arity, and if only one
function has the correct arity, we return it. Otherwise, we weight
functions based on how much work must be done to convert the
arguments, with the following priorities:
* identical types or pointers to identical types
* promotions
* non-Python types
That is, we prefer functions where no arguments need converted,
and failing that, functions where only promotions are required, and
so on.
If no function is deemed a good fit, or if two or more functions have
the same weight, we return None (as there is no best match). If pos
is not None, we also generate an error.
"""
# TODO: args should be a list of types, not a list of Nodes.
actual_nargs = len(args)
candidates = []
errors = []
for func in functions:
error_mesg = ""
func_type = func.type
if func_type.is_ptr:
func_type = func_type.base_type
# Check function type
if not func_type.is_cfunction:
if not func_type.is_error and pos is not None:
error_mesg = "Calling non-function type '%s'" % func_type
errors.append((func, error_mesg))
continue
# Check no. of args
max_nargs = len(func_type.args)
min_nargs = max_nargs - func_type.optional_arg_count
if actual_nargs < min_nargs or \
(not func_type.has_varargs and actual_nargs > max_nargs):
if max_nargs == min_nargs and not func_type.has_varargs:
expectation = max_nargs
elif actual_nargs < min_nargs:
expectation = "at least %s" % min_nargs
else:
expectation = "at most %s" % max_nargs
error_mesg = "Call with wrong number of arguments (expected %s, got %s)" \
% (expectation, actual_nargs)
errors.append((func, error_mesg))
continue
candidates.append((func, func_type))
# Optimize the most common case of no overloading...
if len(candidates) == 1:
return candidates[0][0]
elif len(candidates) == 0:
if pos is not None:
if len(errors) == 1:
error(pos, errors[0][1])
else:
error(pos, "no suitable method found")
return None
possibilities = []
bad_types = []
for func, func_type in candidates:
score = [0,0,0]
for i in range(min(len(args), len(func_type.args))):
src_type = args[i].type
dst_type = func_type.args[i].type
if dst_type.assignable_from(src_type):
if src_type == dst_type or dst_type.same_as(src_type):
pass # score 0
elif is_promotion(src_type, dst_type):
score[2] += 1
elif not src_type.is_pyobject:
score[1] += 1
else:
score[0] += 1
else:
error_mesg = "Invalid conversion from '%s' to '%s'"%(src_type,
dst_type)
bad_types.append((func, error_mesg))
break
else:
possibilities.append((score, func)) # so we can sort it
if possibilities:
possibilities.sort()
if len(possibilities) > 1 and possibilities[0][0] == possibilities[1][0]:
if pos is not None:
error(pos, "ambiguous overloaded method")
return None
return possibilities[0][1]
if pos is not None:
if len(bad_types) == 1:
error(pos, bad_types[0][1])
else:
error(pos, "no suitable method found")
return None
def widest_numeric_type(type1, type2):
# Given two numeric types, return the narrowest type
# encompassing both of them.
if type1 == type2:
widest_type = type1
elif type1.is_complex or type2.is_complex:
def real_type(ntype):
if ntype.is_complex:
return ntype.real_type
return ntype
widest_type = CComplexType(
widest_numeric_type(
real_type(type1),
real_type(type2)))
elif type1.is_enum and type2.is_enum:
widest_type = c_int_type
elif type1.rank < type2.rank:
widest_type = type2
elif type1.rank > type2.rank:
widest_type = type1
elif type1.signed < type2.signed:
widest_type = type1
else:
widest_type = type2
return widest_type
def independent_spanning_type(type1, type2):
# Return a type assignable independently from both type1 and
# type2, but do not require any interoperability between the two.
# For example, in "True * 2", it is safe to assume an integer
# result type (so spanning_type() will do the right thing),
# 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 == type2:
return type1
elif (type1 is c_bint_type or type2 is c_bint_type) and (type1.is_numeric and type2.is_numeric):
# special case: if one of the results is a bint and the other
# is another C integer, we must prevent returning a numeric
# type so that we do not lose the ability to coerce to a
# Python bool if we have to.
return py_object_type
span_type = _spanning_type(type1, type2)
if span_type is None:
return error_type
return span_type
def spanning_type(type1, type2):
# Return a type assignable from both type1 and type2, or
# py_object_type if no better type is found. Assumes that the
# code that calls this will try a coercion afterwards, which will
# fail if the types cannot actually coerce to a py_object_type.
if type1 == type2:
return type1
elif type1 is py_object_type or type2 is py_object_type:
return py_object_type
elif type1 is c_py_unicode_type or type2 is c_py_unicode_type:
# Py_UNICODE behaves more like a string than an int
return py_object_type
span_type = _spanning_type(type1, type2)
if span_type is None:
return py_object_type
return span_type
def _spanning_type(type1, type2):
if type1.is_numeric and type2.is_numeric:
return widest_numeric_type(type1, type2)
elif type1.is_builtin_type and type1.name == 'float' and type2.is_numeric:
return widest_numeric_type(c_double_type, type2)
elif type2.is_builtin_type and type2.name == 'float' and type1.is_numeric:
return widest_numeric_type(type1, c_double_type)
elif type1.is_extension_type and type2.is_extension_type:
return widest_extension_type(type1, type2)
elif type1.is_pyobject or type2.is_pyobject:
return py_object_type
elif type1.assignable_from(type2):
if type1.is_extension_type and type1.typeobj_is_imported():
# external types are unsafe, so we use PyObject instead
return py_object_type
return type1
elif type2.assignable_from(type1):
if type2.is_extension_type and type2.typeobj_is_imported():
# external types are unsafe, so we use PyObject instead
return py_object_type
return type2
else:
return None
def widest_extension_type(type1, type2):
if type1.typeobj_is_imported() or type2.typeobj_is_imported():
return py_object_type
while True:
if type1.subtype_of(type2):
return type2
elif type2.subtype_of(type1):
return type1
type1, type2 = type1.base_type, type2.base_type
if type1 is None or type2 is None:
return py_object_type
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.
return modifiers_and_name_to_type.get((signed, longness, name))
def parse_basic_type(name):
base = None
if name.startswith('p_'):
base = parse_basic_type(name[2:])
elif name.startswith('p'):
base = parse_basic_type(name[1:])
elif name.endswith('*'):
base = parse_basic_type(name[:-1])
if base:
return CPtrType(base)
#
basic_type = simple_c_type(1, 0, name)
if basic_type:
return basic_type
#
signed = 1
longness = 0
if name == 'Py_UNICODE':
signed = 0
elif name == 'Py_ssize_t':
signed = 2
elif name == 'ssize_t':
signed = 2
elif name == 'size_t':
signed = 0
else:
if name.startswith('u'):
name = name[1:]
signed = 0
elif (name.startswith('s') and
not name.startswith('short')):
name = name[1:]
signed = 2
longness = 0
while name.startswith('short'):
name = name.replace('short', '', 1).strip()
longness -= 1
while name.startswith('long'):
name = name.replace('long', '', 1).strip()
longness += 1
if longness != 0 and not name:
name = 'int'
return simple_c_type(signed, longness, name)
def c_array_type(base_type, size):
# Construct a C array type.
if base_type is c_char_type:
return CCharArrayType(size)
elif base_type is error_type:
return error_type
else:
return CArrayType(base_type, size)
def c_ptr_type(base_type):
# Construct a C pointer type.
if base_type is c_char_type:
return c_char_ptr_type
elif base_type is c_uchar_type:
return c_uchar_ptr_type
elif base_type is error_type:
return error_type
else:
return CPtrType(base_type)
def c_ref_type(base_type):
# Construct a C reference type
if base_type is error_type:
return error_type
else:
return CReferenceType(base_type)
def same_type(type1, type2):
return type1.same_as(type2)
def assignable_from(type1, type2):
return type1.assignable_from(type2)
def typecast(to_type, from_type, expr_code):
# Return expr_code cast to a C type which can be
# assigned to to_type, assuming its existing C type
# is from_type.
if to_type is from_type or \
(not to_type.is_pyobject and assignable_from(to_type, from_type)):
return expr_code
else:
#print "typecast: to", to_type, "from", from_type ###
return to_type.cast_code(expr_code)
type_conversion_predeclarations = """
/* Type Conversion Predeclarations */
#define __Pyx_PyBytes_FromUString(s) PyBytes_FromString((char*)s)
#define __Pyx_PyBytes_AsUString(s) ((unsigned char*) PyBytes_AsString(s))
#define __Pyx_PyBool_FromLong(b) ((b) ? (Py_INCREF(Py_True), Py_True) : (Py_INCREF(Py_False), Py_False))
static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*);
static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x);
static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*);
static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t);
static CYTHON_INLINE size_t __Pyx_PyInt_AsSize_t(PyObject*);
#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x))
""" + type_conversion_predeclarations
# Note: __Pyx_PyObject_IsTrue is written to minimize branching.
type_conversion_functions = """
/* Type Conversion Functions */
static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) {
int is_true = x == Py_True;
if (is_true | (x == Py_False) | (x == Py_None)) return is_true;
else return PyObject_IsTrue(x);
}
static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x) {
PyNumberMethods *m;
const char *name = NULL;
PyObject *res = NULL;
#if PY_VERSION_HEX < 0x03000000
if (PyInt_Check(x) || PyLong_Check(x))
#else
if (PyLong_Check(x))
#endif
return Py_INCREF(x), x;
m = Py_TYPE(x)->tp_as_number;
#if PY_VERSION_HEX < 0x03000000
if (m && m->nb_int) {
name = "int";
res = PyNumber_Int(x);
}
else if (m && m->nb_long) {
name = "long";
res = PyNumber_Long(x);
}
#else
if (m && m->nb_int) {
name = "int";
res = PyNumber_Long(x);
}
#endif
if (res) {
#if PY_VERSION_HEX < 0x03000000
if (!PyInt_Check(res) && !PyLong_Check(res)) {
#else
if (!PyLong_Check(res)) {
#endif
PyErr_Format(PyExc_TypeError,
"__%s__ returned non-%s (type %.200s)",
name, name, Py_TYPE(res)->tp_name);
Py_DECREF(res);
return NULL;
}
}
else if (!PyErr_Occurred()) {
PyErr_SetString(PyExc_TypeError,
"an integer is required");
}
return res;
}
static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) {
Py_ssize_t ival;
PyObject* x = PyNumber_Index(b);
if (!x) return -1;
ival = PyInt_AsSsize_t(x);
Py_DECREF(x);
return ival;
}
static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) {
#if PY_VERSION_HEX < 0x02050000
if (ival <= LONG_MAX)
return PyInt_FromLong((long)ival);
else {
unsigned char *bytes = (unsigned char *) &ival;
int one = 1; int little = (int)*(unsigned char*)&one;
return _PyLong_FromByteArray(bytes, sizeof(size_t), little, 0);
}
#else
return PyInt_FromSize_t(ival);
#endif
}
static CYTHON_INLINE size_t __Pyx_PyInt_AsSize_t(PyObject* x) {
unsigned PY_LONG_LONG val = __Pyx_PyInt_AsUnsignedLongLong(x);
if (unlikely(val == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred())) {
return (size_t)-1;
} else if (unlikely(val != (unsigned PY_LONG_LONG)(size_t)val)) {
PyErr_SetString(PyExc_OverflowError,
"value too large to convert to size_t");
return (size_t)-1;
}
return (size_t)val;
}
""" + type_conversion_functions
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Scanning.pxd 0000664 0000000 0000000 00000001560 11446142532 0025241 0 ustar 00root root 0000000 0000000 import cython
from Cython.Plex.Scanners cimport Scanner
cdef class CompileTimeScope:
cdef public entries
cdef public outer
cdef class PyrexScanner(Scanner):
cdef public context
cdef public list included_files
cdef public compile_time_env
cdef public bint compile_time_eval
cdef public bint compile_time_expr
cdef public bint parse_comments
cdef public bint in_python_file
cdef public source_encoding
cdef set keywords
cdef public list indentation_stack
cdef public indentation_char
cdef public int bracket_nesting_level
cdef public sy
cdef public systring
cdef long current_level(self)
cpdef begin(self, state)
cpdef next(self)
cpdef bint expect(self, what, message = *) except -2
@cython.locals(current_level=cython.long, new_level=cython.long)
cpdef indentation_action(self, text)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Scanning.py 0000664 0000000 0000000 00000034051 11446142532 0025077 0 ustar 00root root 0000000 0000000 #
# Cython Scanner
#
import sys
import os
import platform
import cython
cython.declare(EncodedString=object, string_prefixes=object, raw_prefixes=object, IDENT=object,
print_function=object)
from Cython import Plex, Utils
from Cython.Plex.Scanners import Scanner
from Cython.Plex.Errors import UnrecognizedInput
from Errors import CompileError, error
from Lexicon import string_prefixes, raw_prefixes, make_lexicon, IDENT
from Future import print_function
from StringEncoding import EncodedString
debug_scanner = 0
trace_scanner = 0
scanner_debug_flags = 0
scanner_dump_file = None
lexicon = None
def get_lexicon():
global lexicon
if not lexicon:
lexicon = make_lexicon()
return lexicon
#------------------------------------------------------------------
py_reserved_words = [
"global", "def", "class", "print", "del", "pass", "break",
"continue", "return", "raise", "import", "exec", "try",
"except", "finally", "while", "if", "elif", "else", "for",
"in", "assert", "and", "or", "not", "is", "in", "lambda",
"from", "yield", "with", "nonlocal",
]
pyx_reserved_words = py_reserved_words + [
"include", "ctypedef", "cdef", "cpdef",
"cimport", "by", "DEF", "IF", "ELIF", "ELSE"
]
class Method(object):
def __init__(self, name):
self.name = name
self.__name__ = name # for Plex tracing
def __call__(self, stream, text):
return getattr(stream, self.name)(text)
#------------------------------------------------------------------
class CompileTimeScope(object):
def __init__(self, outer = None):
self.entries = {}
self.outer = outer
def declare(self, name, value):
self.entries[name] = value
def lookup_here(self, name):
return self.entries[name]
def __contains__(self, name):
return name in self.entries
def lookup(self, name):
try:
return self.lookup_here(name)
except KeyError:
outer = self.outer
if outer:
return outer.lookup(name)
else:
raise
def initial_compile_time_env():
benv = CompileTimeScope()
names = ('UNAME_SYSNAME', 'UNAME_NODENAME', 'UNAME_RELEASE',
'UNAME_VERSION', 'UNAME_MACHINE')
for name, value in zip(names, platform.uname()):
benv.declare(name, value)
try:
import __builtin__ as builtins
except ImportError:
import builtins
names = ('False', 'True',
'abs', 'bool', 'chr', 'cmp', 'complex', 'dict', 'divmod', 'enumerate',
'float', 'hash', 'hex', 'int', 'len', 'list', 'long', 'map', 'max', 'min',
'oct', 'ord', 'pow', 'range', 'reduce', 'repr', 'round', 'slice', 'str',
'sum', 'tuple', 'xrange', 'zip')
for name in names:
try:
benv.declare(name, getattr(builtins, name))
except AttributeError:
# ignore, likely Py3
pass
denv = CompileTimeScope(benv)
return denv
#------------------------------------------------------------------
class SourceDescriptor(object):
"""
A SourceDescriptor should be considered immutable.
"""
_file_type = 'pyx'
_escaped_description = None
_cmp_name = ''
def __str__(self):
assert False # To catch all places where a descriptor is used directly as a filename
def set_file_type_from_name(self, filename):
name, ext = os.path.splitext(filename)
self._file_type = ext in ('.pyx', '.pxd', '.py') and ext[1:] or 'pyx'
def is_cython_file(self):
return self._file_type in ('pyx', 'pxd')
def is_python_file(self):
return self._file_type == 'py'
def get_escaped_description(self):
if self._escaped_description is None:
self._escaped_description = \
self.get_description().encode('ASCII', 'replace').decode("ASCII")
return self._escaped_description
def __gt__(self, other):
# this is only used to provide some sort of order
try:
return self._cmp_name > other._cmp_name
except AttributeError:
return False
def __lt__(self, other):
# this is only used to provide some sort of order
try:
return self._cmp_name < other._cmp_name
except AttributeError:
return False
def __le__(self, other):
# this is only used to provide some sort of order
try:
return self._cmp_name <= other._cmp_name
except AttributeError:
return False
class FileSourceDescriptor(SourceDescriptor):
"""
Represents a code source. A code source is a more generic abstraction
for a "filename" (as sometimes the code doesn't come from a file).
Instances of code sources are passed to Scanner.__init__ as the
optional name argument and will be passed back when asking for
the position()-tuple.
"""
def __init__(self, filename):
filename = Utils.decode_filename(filename)
self.filename = filename
self.set_file_type_from_name(filename)
self._cmp_name = filename
def get_lines(self, encoding=None, error_handling=None):
return Utils.open_source_file(
self.filename, encoding=encoding,
error_handling=error_handling,
# newline normalisation is costly before Py2.6
require_normalised_newlines=False)
def get_description(self):
return self.filename
def get_filenametable_entry(self):
return self.filename
def __eq__(self, other):
return isinstance(other, FileSourceDescriptor) and self.filename == other.filename
def __hash__(self):
return hash(self.filename)
def __repr__(self):
return "" % self.filename
class StringSourceDescriptor(SourceDescriptor):
"""
Instances of this class can be used instead of a filenames if the
code originates from a string object.
"""
def __init__(self, name, code):
self.name = name
#self.set_file_type_from_name(name)
self.codelines = [x + "\n" for x in code.split("\n")]
self._cmp_name = name
def get_lines(self, encoding=None, error_handling=None):
if not encoding:
return self.codelines
else:
return [ line.encode(encoding, error_handling).decode(encoding)
for line in self.codelines ]
def get_description(self):
return self.name
def get_filenametable_entry(self):
return "stringsource"
def __hash__(self):
return hash(self.name)
def __eq__(self, other):
return isinstance(other, StringSourceDescriptor) and self.name == other.name
def __repr__(self):
return "" % self.name
#------------------------------------------------------------------
class PyrexScanner(Scanner):
# context Context Compilation context
# included_files [string] Files included with 'include' statement
# compile_time_env dict Environment for conditional compilation
# 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):
Scanner.__init__(self, get_lexicon(), file, filename, initial_pos)
if parent_scanner:
self.context = parent_scanner.context
self.included_files = parent_scanner.included_files
self.compile_time_env = parent_scanner.compile_time_env
self.compile_time_eval = parent_scanner.compile_time_eval
self.compile_time_expr = parent_scanner.compile_time_expr
else:
self.context = context
self.included_files = scope.included_files
self.compile_time_env = initial_compile_time_env()
self.compile_time_eval = 1
self.compile_time_expr = 0
self.parse_comments = parse_comments
self.source_encoding = source_encoding
if filename.is_python_file():
self.in_python_file = True
self.keywords = cython.set(py_reserved_words)
else:
self.in_python_file = False
self.keywords = cython.set(pyx_reserved_words)
self.trace = trace_scanner
self.indentation_stack = [0]
self.indentation_char = None
self.bracket_nesting_level = 0
self.begin('INDENT')
self.sy = ''
self.next()
def commentline(self, text):
if self.parse_comments:
self.produce('commentline', text)
def current_level(self):
return self.indentation_stack[-1]
def open_bracket_action(self, text):
self.bracket_nesting_level = self.bracket_nesting_level + 1
return text
def close_bracket_action(self, text):
self.bracket_nesting_level = self.bracket_nesting_level - 1
return text
def newline_action(self, text):
if self.bracket_nesting_level == 0:
self.begin('INDENT')
self.produce('NEWLINE', '')
string_states = {
"'": 'SQ_STRING',
'"': 'DQ_STRING',
"'''": 'TSQ_STRING',
'"""': 'TDQ_STRING'
}
def begin_string_action(self, text):
if text[:1] in string_prefixes:
text = text[1:]
if text[:1] in raw_prefixes:
text = text[1:]
self.begin(self.string_states[text])
self.produce('BEGIN_STRING')
def end_string_action(self, text):
self.begin('')
self.produce('END_STRING')
def unclosed_string_action(self, text):
self.end_string_action(text)
self.error("Unclosed string literal")
def indentation_action(self, text):
self.begin('')
# Indentation within brackets should be ignored.
#if self.bracket_nesting_level > 0:
# return
# Check that tabs and spaces are being used consistently.
if text:
c = text[0]
#print "Scanner.indentation_action: indent with", repr(c) ###
if self.indentation_char is None:
self.indentation_char = c
#print "Scanner.indentation_action: setting indent_char to", repr(c)
else:
if self.indentation_char != c:
self.error("Mixed use of tabs and spaces")
if text.replace(c, "") != "":
self.error("Mixed use of tabs and spaces")
# Figure out how many indents/dedents to do
current_level = self.current_level()
new_level = len(text)
#print "Changing indent level from", current_level, "to", new_level ###
if new_level == current_level:
return
elif new_level > current_level:
#print "...pushing level", new_level ###
self.indentation_stack.append(new_level)
self.produce('INDENT', '')
else:
while new_level < self.current_level():
#print "...popping level", self.indentation_stack[-1] ###
self.indentation_stack.pop()
self.produce('DEDENT', '')
#print "...current level now", self.current_level() ###
if new_level != self.current_level():
self.error("Inconsistent indentation")
def eof_action(self, text):
while len(self.indentation_stack) > 1:
self.produce('DEDENT', '')
self.indentation_stack.pop()
self.produce('EOF', '')
def next(self):
try:
sy, systring = self.read()
except UnrecognizedInput:
self.error("Unrecognized character")
if sy == IDENT:
if systring in self.keywords:
if systring == 'print' and \
print_function in self.context.future_directives:
systring = EncodedString(systring)
else:
sy = systring
else:
systring = EncodedString(systring)
self.sy = sy
self.systring = systring
if False: # debug_scanner:
_, line, col = self.position()
if not self.systring or self.sy == self.systring:
t = self.sy
else:
t = "%s %s" % (self.sy, self.systring)
print("--- %3d %2d %s" % (line, col, t))
def peek(self):
saved = self.sy, self.systring
self.next()
next = self.sy, self.systring
self.unread(*next)
self.sy, self.systring = saved
return next
def put_back(self, sy, systring):
self.unread(self.sy, self.systring)
self.sy = sy
self.systring = systring
def unread(self, token, value):
# This method should be added to Plex
self.queue.insert(0, (token, value))
def error(self, message, pos = None, fatal = True):
if pos is None:
pos = self.position()
if self.sy == 'INDENT':
err = error(pos, "Possible inconsistent indentation")
err = error(pos, message)
if fatal: raise err
def expect(self, what, message = None):
if self.sy == what:
self.next()
else:
self.expected(what, message)
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):
if message:
self.error(message)
else:
self.error("Expected '%s'" % what)
def expect_indent(self):
self.expect('INDENT',
"Expected an increase in indentation level")
def expect_dedent(self):
self.expect('DEDENT',
"Expected a decrease in indentation level")
def expect_newline(self, message = "Expected a newline"):
# Expect either a newline or end of file
if self.sy != 'EOF':
self.expect('NEWLINE', message)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/StringEncoding.py 0000664 0000000 0000000 00000015722 11446142532 0026260 0 ustar 00root root 0000000 0000000 #
# Cython -- encoding related tools
#
import re
import sys
if sys.version_info[0] >= 3:
_unicode, _str, _bytes = str, str, bytes
IS_PYTHON3 = True
else:
_unicode, _str, _bytes = unicode, str, str
IS_PYTHON3 = False
empty_bytes = _bytes()
empty_unicode = _unicode()
join_bytes = empty_bytes.join
class UnicodeLiteralBuilder(object):
"""Assemble a unicode string.
"""
def __init__(self):
self.chars = []
def append(self, characters):
if isinstance(characters, _bytes):
# this came from a Py2 string literal in the parser code
characters = characters.decode("ASCII")
assert isinstance(characters, _unicode), str(type(characters))
self.chars.append(characters)
if sys.maxunicode == 65535:
def append_charval(self, char_number):
if char_number > 65535:
# 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) )
else:
self.chars.append( unichr(char_number) )
else:
def append_charval(self, char_number):
self.chars.append( unichr(char_number) )
def append_uescape(self, char_number, escape_string):
self.append_charval(char_number)
def getstring(self):
return EncodedString(u''.join(self.chars))
def getstrings(self):
return (None, self.getstring())
class BytesLiteralBuilder(object):
"""Assemble a byte string or char value.
"""
def __init__(self, target_encoding):
self.chars = []
self.target_encoding = target_encoding
def append(self, characters):
if isinstance(characters, _unicode):
characters = characters.encode(self.target_encoding)
assert isinstance(characters, _bytes), str(type(characters))
self.chars.append(characters)
def append_charval(self, char_number):
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!
s = BytesLiteral(join_bytes(self.chars))
s.encoding = self.target_encoding
return s
def getchar(self):
# this *must* return a byte string!
return self.getstring()
def getstrings(self):
return (self.getstring(), None)
class StrLiteralBuilder(object):
"""Assemble both a bytes and a unicode representation of a string.
"""
def __init__(self, target_encoding):
self._bytes = BytesLiteralBuilder(target_encoding)
self._unicode = UnicodeLiteralBuilder()
def append(self, characters):
self._bytes.append(characters)
self._unicode.append(characters)
def append_charval(self, char_number):
self._bytes.append_charval(char_number)
self._unicode.append_charval(char_number)
def append_uescape(self, char_number, escape_string):
self._bytes.append(escape_string)
self._unicode.append_charval(char_number)
def getstrings(self):
return (self._bytes.getstring(), self._unicode.getstring())
class EncodedString(_unicode):
# unicode string subclass to keep track of the original encoding.
# 'encoding' is None for unicode strings and the source encoding
# otherwise
encoding = None
def byteencode(self):
assert self.encoding is not None
return self.encode(self.encoding)
def utf8encode(self):
assert self.encoding is None
return self.encode("UTF-8")
def is_unicode(self):
return self.encoding is None
is_unicode = property(is_unicode)
class BytesLiteral(_bytes):
# bytes subclass that is compatible with EncodedString
encoding = None
def byteencode(self):
if IS_PYTHON3:
return _bytes(self)
else:
# fake-recode the string to make it a plain bytes object
return self.decode('ISO-8859-1').encode('ISO-8859-1')
def utf8encode(self):
assert False, "this is not a unicode string: %r" % self
def __str__(self):
"""Fake-decode the byte string to unicode to support %
formatting of unicode strings.
"""
return self.decode('ISO-8859-1')
is_unicode = False
char_from_escape_sequence = {
r'\a' : u'\a',
r'\b' : u'\b',
r'\f' : u'\f',
r'\n' : u'\n',
r'\r' : u'\r',
r'\t' : u'\t',
r'\v' : u'\v',
}.get
def _to_escape_sequence(s):
if s in '\n\r\t':
return repr(s)[1:-1]
elif s == '"':
return r'\"'
elif s == '\\':
return r'\\'
else:
# within a character sequence, oct passes much better than hex
return ''.join(['\\%03o' % ord(c) for c in s])
_c_special = ('\\', '??', '"') + tuple(map(chr, range(32)))
_c_special_replacements = [(orig.encode('ASCII'),
_to_escape_sequence(orig).encode('ASCII'))
for orig in _c_special ]
def _build_specials_test():
subexps = []
for special in _c_special:
regexp = ''.join(['[%s]' % c.replace('\\', '\\\\') for c in special])
subexps.append(regexp)
return re.compile('|'.join(subexps).encode('ASCII')).search
_has_specials = _build_specials_test()
def escape_char(c):
if IS_PYTHON3:
c = c.decode('ISO-8859-1')
if c in '\n\r\t\\':
return repr(c)[1:-1]
elif c == "'":
return "\\'"
n = ord(c)
if n < 32 or n > 127:
# hex works well for characters
return "\\x%02X" % n
else:
return c
def escape_byte_string(s):
"""Escape a byte string so that it can be written into C code.
Note that this returns a Unicode string instead which, when
encoded as ISO-8859-1, will result in the correct byte sequence
being written.
"""
if _has_specials(s):
for special, replacement in _c_special_replacements:
if special in s:
s = s.replace(special, replacement)
try:
return s.decode("ASCII") # trial decoding: plain ASCII => done
except UnicodeDecodeError:
pass
if IS_PYTHON3:
s_new = bytearray()
append, extend = s_new.append, s_new.extend
for b in s:
if b >= 128:
extend(('\\%3o' % b).encode('ASCII'))
else:
append(b)
return s_new.decode('ISO-8859-1')
else:
l = []
append = l.append
for c in s:
o = ord(c)
if o >= 128:
append('\\%3o' % o)
else:
append(c)
return join_bytes(l).decode('ISO-8859-1')
def split_string_literal(s):
# MSVC can't handle long string literals.
if len(s) < 2047:
return s
else:
return '""'.join([s[i:i+2000] for i in range(0, len(s), 2000)]).replace(r'\""', '""\\')
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Symtab.py 0000664 0000000 0000000 00000224527 11446142532 0024607 0 ustar 00root root 0000000 0000000 #
# Symbol Table
#
import re
from Cython import Utils
from Errors import warning, error, InternalError
from StringEncoding import EncodedString
import Options, Naming
import PyrexTypes
from PyrexTypes import py_object_type, unspecified_type
import TypeSlots
from TypeSlots import \
pyfunction_signature, pymethod_signature, \
get_special_method_signature, get_property_accessor_signature
import ControlFlow
import Code
import __builtin__ as builtins
try:
set
except NameError:
from sets import Set as set
import copy
possible_identifier = re.compile(ur"(?![0-9])\w+$", re.U).match
nice_identifier = re.compile('^[a-zA-Z0-0_]+$').match
iso_c99_keywords = set(
['auto', 'break', 'case', 'char', 'const', 'continue', 'default', 'do',
'double', 'else', 'enum', 'extern', 'float', 'for', 'goto', 'if',
'int', 'long', 'register', 'return', 'short', 'signed', 'sizeof',
'static', 'struct', 'switch', 'typedef', 'union', 'unsigned', 'void',
'volatile', 'while',
'_Bool', '_Complex'', _Imaginary', 'inline', 'restrict'])
def c_safe_identifier(cname):
# There are some C limitations on struct entry names.
if ((cname[:2] == '__'
and not (cname.startswith(Naming.pyrex_prefix)
or cname == '__weakref__'))
or cname in iso_c99_keywords):
cname = Naming.pyrex_prefix + cname
return cname
class BufferAux(object):
writable_needed = False
def __init__(self, buffer_info_var, stridevars, shapevars,
suboffsetvars):
self.buffer_info_var = buffer_info_var
self.stridevars = stridevars
self.shapevars = shapevars
self.suboffsetvars = suboffsetvars
def __repr__(self):
return "" % self.__dict__
class Entry(object):
# A symbol table entry in a Scope or ModuleNamespace.
#
# name string Python name of entity
# cname string C name of entity
# type PyrexType Type of entity
# doc string Doc string
# init string Initial value
# visibility 'private' or 'public' or 'extern'
# is_builtin boolean Is an entry in the Python builtins dict
# is_cglobal boolean Is a C global variable
# is_pyglobal boolean Is a Python module-level variable
# or class attribute during
# class construction
# is_member boolean Is an assigned class member
# is_variable boolean Is a variable
# is_cfunction boolean Is a C function
# is_cmethod boolean Is a C method of an extension type
# is_unbound_cmethod boolean Is an unbound C method of an extension type
# is_type boolean Is a type definition
# is_cclass boolean Is an extension class
# is_cpp_class boolean Is a C++ class
# is_const boolean Is a constant
# is_property boolean Is a property of an extension type:
# doc_cname string or None C const holding the docstring
# getter_cname string C func for getting property
# setter_cname string C func for setting or deleting property
# is_self_arg boolean Is the "self" arg of an exttype method
# is_arg boolean Is the arg of a method
# is_local boolean Is a local variable
# in_closure boolean Is referenced in an inner scope
# is_readonly boolean Can't be assigned to
# func_cname string C func implementing Python func
# func_modifiers [string] C function modifiers ('inline')
# pos position Source position where declared
# namespace_cname string If is_pyglobal, the C variable
# holding its home namespace
# pymethdef_cname string PyMethodDef structure
# signature Signature Arg & return types for Python func
# init_to_none boolean True if initial value should be None
# as_variable Entry Alternative interpretation of extension
# type name or builtin C function as a variable
# xdecref_cleanup boolean Use Py_XDECREF for error cleanup
# in_cinclude boolean Suppress C declaration code
# enum_values [Entry] For enum types, list of values
# qualified_name string "modname.funcname" or "modname.classname"
# or "modname.classname.funcname"
# is_declared_generic boolean Is declared as PyObject * even though its
# type is an extension type
# as_module None Module scope, if a cimported module
# is_inherited boolean Is an inherited attribute of an extension type
# pystring_cname string C name of Python version of string literal
# is_interned boolean For string const entries, value is interned
# is_identifier boolean For string const entries, value is an identifier
# used boolean
# is_special boolean Is a special method or property accessor
# of an extension type
# defined_in_pxd boolean Is defined in a .pxd file (not just declared)
# api boolean Generate C API for C class or function
# utility_code string Utility code needed when this entry is used
#
# buffer_aux BufferAux or None Extra information needed for buffer variables
# inline_func_in_pxd boolean Hacky special case for inline function in pxd file.
# Ideally this should not be necesarry.
# assignments [ExprNode] List of expressions that get assigned to this entry.
# might_overflow boolean In an arithmetic expression that could cause
# overflow (used for type inference).
inline_func_in_pxd = False
borrowed = 0
init = ""
visibility = 'private'
is_builtin = 0
is_cglobal = 0
is_pyglobal = 0
is_member = 0
is_variable = 0
is_cfunction = 0
is_cmethod = 0
is_unbound_cmethod = 0
is_type = 0
is_cclass = 0
is_cpp_class = 0
is_const = 0
is_property = 0
doc_cname = None
getter_cname = None
setter_cname = None
is_self_arg = 0
is_arg = 0
is_local = 0
in_closure = 0
from_closure = 0
is_declared_generic = 0
is_readonly = 0
func_cname = None
func_modifiers = []
doc = None
init_to_none = 0
as_variable = None
xdecref_cleanup = 0
in_cinclude = 0
as_module = None
is_inherited = 0
pystring_cname = None
is_identifier = 0
is_interned = 0
used = 0
is_special = 0
defined_in_pxd = 0
is_implemented = 0
api = 0
utility_code = None
is_overridable = 0
buffer_aux = None
prev_entry = None
might_overflow = 0
def __init__(self, name, cname, type, pos = None, init = None):
self.name = name
self.cname = cname
self.type = type
self.pos = pos
self.init = init
self.overloaded_alternatives = []
self.assignments = []
def __repr__(self):
return "Entry(name=%s, type=%s)" % (self.name, self.type)
def redeclared(self, pos):
error(pos, "'%s' does not match previous declaration" % self.name)
error(self.pos, "Previous declaration is here")
def all_alternatives(self):
return [self] + self.overloaded_alternatives
class Scope(object):
# name string Unqualified name
# outer_scope Scope or None Enclosing scope
# entries {string : Entry} Python name to entry, non-types
# const_entries [Entry] Constant entries
# type_entries [Entry] Struct/union/enum/typedef/exttype entries
# sue_entries [Entry] Struct/union/enum entries
# arg_entries [Entry] Function argument entries
# var_entries [Entry] User-defined variable entries
# pyfunc_entries [Entry] Python function entries
# cfunc_entries [Entry] C function entries
# c_class_entries [Entry] All extension type entries
# cname_to_entry {string : Entry} Temp cname to entry mapping
# int_to_entry {int : Entry} Temp cname to entry mapping
# return_type PyrexType or None Return type of function owning scope
# is_py_class_scope boolean Is a Python class scope
# is_c_class_scope boolean Is an extension type scope
# is_closure_scope boolean
# is_cpp_class_scope boolean Is a C++ class scope
# is_property_scope boolean Is a extension type property scope
# scope_prefix string Disambiguator for C names
# in_cinclude boolean Suppress C declaration code
# qualified_name string "modname" or "modname.classname"
# pystring_entries [Entry] String const entries newly used as
# Python strings in this scope
# control_flow ControlFlow Used for keeping track of environment state
# nogil boolean In a nogil section
# directives dict Helper variable for the recursive
# analysis, contains directive values.
# is_internal boolean Is only used internally (simpler setup)
is_py_class_scope = 0
is_c_class_scope = 0
is_closure_scope = 0
is_cpp_class_scope = 0
is_property_scope = 0
is_module_scope = 0
is_internal = 0
scope_prefix = ""
in_cinclude = 0
nogil = 0
def __init__(self, name, outer_scope, parent_scope):
# The outer_scope is the next scope in the lookup chain.
# The parent_scope is used to derive the qualified name of this scope.
self.name = name
self.outer_scope = outer_scope
self.parent_scope = parent_scope
mangled_name = "%d%s_" % (len(name), name)
qual_scope = self.qualifying_scope()
if qual_scope:
self.qualified_name = qual_scope.qualify_name(name)
self.scope_prefix = qual_scope.scope_prefix + mangled_name
else:
self.qualified_name = name
self.scope_prefix = mangled_name
self.entries = {}
self.const_entries = []
self.type_entries = []
self.sue_entries = []
self.arg_entries = []
self.var_entries = []
self.pyfunc_entries = []
self.cfunc_entries = []
self.c_class_entries = []
self.defined_c_classes = []
self.imported_c_classes = {}
self.cname_to_entry = {}
self.string_to_entry = {}
self.identifier_to_entry = {}
self.num_to_entry = {}
self.obj_to_entry = {}
self.pystring_entries = []
self.buffer_entries = []
self.lambda_defs = []
self.control_flow = ControlFlow.LinearControlFlow()
self.return_type = None
self.id_counters = {}
def start_branching(self, pos):
self.control_flow = self.control_flow.start_branch(pos)
def next_branch(self, pos):
self.control_flow = self.control_flow.next_branch(pos)
def finish_branching(self, pos):
self.control_flow = self.control_flow.finish_branch(pos)
def __str__(self):
return "<%s %s>" % (self.__class__.__name__, self.qualified_name)
def qualifying_scope(self):
return self.parent_scope
def mangle(self, prefix, name = None):
if name:
return "%s%s%s" % (prefix, self.scope_prefix, name)
else:
return self.parent_scope.mangle(prefix, self.name)
def mangle_internal(self, name):
# Mangle an internal name so as not to clash with any
# user-defined name in this scope.
prefix = "%s%s_" % (Naming.pyrex_prefix, name)
return self.mangle(prefix)
#return self.parent_scope.mangle(prefix, self.name)
def next_id(self, name=None):
# Return a cname fragment that is unique for this scope.
try:
count = self.id_counters[name] + 1
except KeyError:
count = 0
self.id_counters[name] = count
if name:
return '%s%d' % (name, count)
else:
return '%d' % count
def global_scope(self):
# Return the module-level scope containing this scope.
return self.outer_scope.global_scope()
def builtin_scope(self):
# Return the module-level scope containing this scope.
return self.outer_scope.builtin_scope()
def declare(self, name, cname, type, pos, visibility):
# Create new entry, and add to dictionary if
# name is not None. Reports a warning if already
# declared.
if type.is_buffer and not isinstance(self, LocalScope):
error(pos, ERR_BUF_LOCALONLY)
if not self.in_cinclude and cname and re.match("^_[_A-Z]+$", cname):
# See http://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html#Reserved-Names
warning(pos, "'%s' is a reserved name in C." % cname, -1)
entries = self.entries
if name and name in entries:
if visibility == 'extern':
warning(pos, "'%s' redeclared " % name, 0)
elif visibility != 'ignore':
error(pos, "'%s' redeclared " % name)
entry = Entry(name, cname, type, pos = pos)
entry.in_cinclude = self.in_cinclude
if name:
entry.qualified_name = self.qualify_name(name)
# if name in entries and self.is_cpp():
# entries[name].overloaded_alternatives.append(entry)
# else:
# entries[name] = entry
entries[name] = entry
entry.scope = self
entry.visibility = visibility
return entry
def qualify_name(self, name):
return "%s.%s" % (self.qualified_name, name)
def declare_const(self, name, type, value, pos, cname = None, visibility = 'private'):
# Add an entry for a named constant.
if not cname:
if self.in_cinclude or visibility == 'public':
cname = name
else:
cname = self.mangle(Naming.enum_prefix, name)
entry = self.declare(name, cname, type, pos, visibility)
entry.is_const = 1
entry.value_node = value
return entry
def declare_type(self, name, type, pos,
cname = None, visibility = 'private', defining = 1):
# Add an entry for a type definition.
if not cname:
cname = name
entry = self.declare(name, cname, type, pos, visibility)
entry.is_type = 1
if defining:
self.type_entries.append(entry)
# here we would set as_variable to an object representing this type
return entry
def declare_typedef(self, name, base_type, pos, cname = None,
visibility = 'private'):
if not cname:
if self.in_cinclude or visibility == 'public':
cname = name
else:
cname = self.mangle(Naming.type_prefix, name)
try:
type = PyrexTypes.create_typedef_type(name, base_type, cname,
(visibility == 'extern'))
except ValueError, e:
error(pos, e.args[0])
type = PyrexTypes.error_type
entry = self.declare_type(name, type, pos, cname, visibility)
type.qualified_name = entry.qualified_name
return entry
def declare_struct_or_union(self, name, kind, scope,
typedef_flag, pos, cname = None, visibility = 'private',
packed = False):
# Add an entry for a struct or union definition.
if not cname:
if self.in_cinclude or visibility == 'public':
cname = name
else:
cname = self.mangle(Naming.type_prefix, name)
entry = self.lookup_here(name)
if not entry:
type = PyrexTypes.CStructOrUnionType(
name, kind, scope, typedef_flag, cname, packed)
entry = self.declare_type(name, type, pos, cname,
visibility = visibility, defining = scope is not None)
self.sue_entries.append(entry)
type.entry = entry
else:
if not (entry.is_type and entry.type.is_struct_or_union
and entry.type.kind == kind):
warning(pos, "'%s' redeclared " % name, 0)
elif scope and entry.type.scope:
warning(pos, "'%s' already defined (ignoring second definition)" % name, 0)
else:
self.check_previous_typedef_flag(entry, typedef_flag, pos)
self.check_previous_visibility(entry, visibility, pos)
if scope:
entry.type.scope = scope
self.type_entries.append(entry)
if not scope and not entry.type.scope:
self.check_for_illegal_incomplete_ctypedef(typedef_flag, pos)
return entry
def declare_cpp_class(self, name, scope,
pos, cname = None, base_classes = [],
visibility = 'extern', templates = None):
if visibility != 'extern':
error(pos, "C++ classes may only be extern")
if cname is None:
cname = name
entry = self.lookup_here(name)
if not entry:
type = PyrexTypes.CppClassType(
name, scope, cname, base_classes, templates = templates)
entry = self.declare_type(name, type, pos, cname,
visibility = visibility, defining = scope is not None)
else:
if not (entry.is_type and entry.type.is_cpp_class):
warning(pos, "'%s' redeclared " % name, 0)
elif scope and entry.type.scope:
warning(pos, "'%s' already defined (ignoring second definition)" % name, 0)
else:
if scope:
entry.type.scope = scope
self.type_entries.append(entry)
if templates is not None:
for T in templates:
template_entry = entry.type.scope.declare(T.name, T.name, T, None, 'extern')
template_entry.is_type = 1
def declare_inherited_attributes(entry, base_classes):
for base_class in base_classes:
declare_inherited_attributes(entry, base_class.base_classes)
entry.type.scope.declare_inherited_cpp_attributes(base_class.scope)
if entry.type.scope:
declare_inherited_attributes(entry, base_classes)
if self.is_cpp_class_scope:
entry.type.namespace = self.outer_scope.lookup(self.name).type
return entry
def check_previous_typedef_flag(self, entry, typedef_flag, pos):
if typedef_flag != entry.type.typedef_flag:
error(pos, "'%s' previously declared using '%s'" % (
entry.name, ("cdef", "ctypedef")[entry.type.typedef_flag]))
def check_previous_visibility(self, entry, visibility, pos):
if entry.visibility != visibility:
error(pos, "'%s' previously declared as '%s'" % (
entry.name, entry.visibility))
def declare_enum(self, name, pos, cname, typedef_flag,
visibility = 'private'):
if name:
if not cname:
if self.in_cinclude or visibility == 'public':
cname = name
else:
cname = self.mangle(Naming.type_prefix, name)
type = PyrexTypes.CEnumType(name, cname, typedef_flag)
else:
type = PyrexTypes.c_anon_enum_type
entry = self.declare_type(name, type, pos, cname = cname,
visibility = visibility)
entry.enum_values = []
self.sue_entries.append(entry)
return entry
def declare_var(self, name, type, pos,
cname = None, visibility = 'private', is_cdef = 0):
# Add an entry for a variable.
if not cname:
if visibility != 'private':
cname = name
else:
cname = self.mangle(Naming.var_prefix, name)
if type.is_cpp_class and visibility != 'extern':
constructor = type.scope.lookup(u'')
if constructor is not None and PyrexTypes.best_match([], constructor.all_alternatives()) is None:
error(pos, "C++ class must have a default constructor to be stack allocated")
entry = self.declare(name, cname, type, pos, visibility)
entry.is_variable = 1
self.control_flow.set_state((), (name, 'initialized'), False)
return entry
def declare_builtin(self, name, pos):
return self.outer_scope.declare_builtin(name, pos)
def declare_pyfunction(self, name, pos):
# Add an entry for a Python function.
entry = self.lookup_here(name)
if entry and not entry.type.is_cfunction:
# This is legal Python, but for now will produce invalid C.
error(pos, "'%s' already declared" % name)
entry = self.declare_var(name, py_object_type, pos, visibility='extern')
entry.signature = pyfunction_signature
self.pyfunc_entries.append(entry)
return entry
def declare_lambda_function(self, func_cname, pos):
# Add an entry for an anonymous Python function.
entry = self.declare_var(None, py_object_type, pos,
cname=func_cname, visibility='private')
entry.name = EncodedString(func_cname)
entry.func_cname = func_cname
entry.signature = pyfunction_signature
self.pyfunc_entries.append(entry)
return entry
def add_lambda_def(self, def_node):
self.lambda_defs.append(def_node)
def register_pyfunction(self, entry):
self.pyfunc_entries.append(entry)
def declare_cfunction(self, name, type, pos,
cname = None, visibility = 'private', defining = 0,
api = 0, in_pxd = 0, modifiers = ()):
# Add an entry for a C function.
if not cname:
if api or visibility != 'private':
cname = name
else:
cname = self.mangle(Naming.func_prefix, name)
entry = self.lookup_here(name)
if entry:
if visibility != 'private' and visibility != entry.visibility:
warning(pos, "Function '%s' previously declared as '%s'" % (name, entry.visibility), 1)
if not entry.type.same_as(type):
if visibility == 'extern' and entry.visibility == 'extern':
if self.is_cpp():
temp = self.add_cfunction(name, type, pos, cname, visibility, modifiers)
temp.overloaded_alternatives = entry.all_alternatives()
entry = temp
else:
warning(pos, "Function signature does not match previous declaration", 1)
entry.type = type
else:
error(pos, "Function signature does not match previous declaration")
else:
entry = self.add_cfunction(name, type, pos, cname, visibility, modifiers)
entry.func_cname = cname
if in_pxd and visibility != 'extern':
entry.defined_in_pxd = 1
if api:
entry.api = 1
if not defining and not in_pxd and visibility != 'extern':
error(pos, "Non-extern C function '%s' declared but not defined" % name)
if defining:
entry.is_implemented = True
if modifiers:
entry.func_modifiers = modifiers
return entry
def add_cfunction(self, name, type, pos, cname, visibility, modifiers):
# Add a C function entry without giving it a func_cname.
entry = self.declare(name, cname, type, pos, visibility)
entry.is_cfunction = 1
if modifiers:
entry.func_modifiers = modifiers
self.cfunc_entries.append(entry)
return entry
def find(self, name, pos):
# Look up name, report error if not found.
entry = self.lookup(name)
if entry:
return entry
else:
error(pos, "'%s' is not declared" % name)
def find_imported_module(self, path, pos):
# Look up qualified name, must be a module, report error if not found.
# Path is a list of names.
scope = self
for name in path:
entry = scope.find(name, pos)
if not entry:
return None
if entry.as_module:
scope = entry.as_module
else:
error(pos, "'%s' is not a cimported module" % '.'.join(path))
return None
return scope
def lookup(self, name):
# Look up name in this scope or an enclosing one.
# Return None if not found.
return (self.lookup_here(name)
or (self.outer_scope and self.outer_scope.lookup(name))
or None)
def lookup_here(self, name):
# Look up in this scope only, return None if not found.
return self.entries.get(name, None)
def lookup_target(self, name):
# Look up name in this scope only. Declare as Python
# variable if not found.
entry = self.lookup_here(name)
if not entry:
entry = self.declare_var(name, py_object_type, None)
return entry
def lookup_type(self, name):
entry = self.lookup(name)
if entry and entry.is_type:
return entry.type
def lookup_operator(self, operator, operands):
if operands[0].type.is_cpp_class:
obj_type = operands[0].type
method = obj_type.scope.lookup("operator%s" % operator)
if method is not None:
res = PyrexTypes.best_match(operands[1:], method.all_alternatives())
if res is not None:
return res
function = self.lookup("operator%s" % operator)
if function is None:
return None
return PyrexTypes.best_match(operands, function.all_alternatives())
def use_utility_code(self, new_code):
self.global_scope().use_utility_code(new_code)
def generate_library_function_declarations(self, code):
# Generate extern decls for C library funcs used.
pass
def defines_any(self, names):
# Test whether any of the given names are
# defined in this scope.
for name in names:
if name in self.entries:
return 1
return 0
def infer_types(self):
from TypeInference import get_type_inferer
get_type_inferer().infer_types(self)
def is_cpp(self):
outer = self.outer_scope
if outer is None:
return False
else:
return outer.is_cpp()
class PreImportScope(Scope):
namespace_cname = Naming.preimport_cname
def __init__(self):
Scope.__init__(self, Options.pre_import, None, None)
def declare_builtin(self, name, pos):
entry = self.declare(name, name, py_object_type, pos, 'private')
entry.is_variable = True
entry.is_pyglobal = True
return entry
class BuiltinScope(Scope):
# The builtin namespace.
def __init__(self):
if Options.pre_import is None:
Scope.__init__(self, "__builtin__", None, None)
else:
Scope.__init__(self, "__builtin__", PreImportScope(), None)
self.type_names = {}
for name, definition in self.builtin_entries.iteritems():
cname, type = definition
self.declare_var(name, type, None, cname)
def declare_builtin(self, name, pos):
if not hasattr(builtins, name):
if self.outer_scope is not None:
return self.outer_scope.declare_builtin(name, pos)
else:
error(pos, "undeclared name not builtin: %s"%name)
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')
entry.utility_code = utility_code
if python_equiv:
if python_equiv == "*":
python_equiv = name
else:
python_equiv = EncodedString(python_equiv)
var_entry = Entry(python_equiv, python_equiv, py_object_type)
var_entry.is_variable = 1
var_entry.is_builtin = 1
var_entry.utility_code = utility_code
entry.as_variable = var_entry
return entry
def declare_builtin_type(self, name, cname, utility_code = None):
name = EncodedString(name)
type = PyrexTypes.BuiltinObjectType(name, cname)
type.set_scope(CClassScope(name, outer_scope=None, visibility='extern'))
self.type_names[name] = 1
entry = self.declare_type(name, type, None, visibility='extern')
entry.utility_code = utility_code
var_entry = Entry(name = entry.name,
type = self.lookup('type').type, # make sure "type" is the first type declared...
pos = entry.pos,
cname = "((PyObject*)%s)" % entry.type.typeptr_cname)
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
entry.as_variable = var_entry
return type
def builtin_scope(self):
return self
builtin_entries = {
"type": ["((PyObject*)&PyType_Type)", py_object_type],
"bool": ["((PyObject*)&PyBool_Type)", py_object_type],
"int": ["((PyObject*)&PyInt_Type)", py_object_type],
"long": ["((PyObject*)&PyLong_Type)", py_object_type],
"float": ["((PyObject*)&PyFloat_Type)", py_object_type],
"complex":["((PyObject*)&PyComplex_Type)", py_object_type],
"bytes": ["((PyObject*)&PyBytes_Type)", py_object_type],
"str": ["((PyObject*)&PyString_Type)", py_object_type],
"unicode":["((PyObject*)&PyUnicode_Type)", py_object_type],
"tuple": ["((PyObject*)&PyTuple_Type)", py_object_type],
"list": ["((PyObject*)&PyList_Type)", py_object_type],
"dict": ["((PyObject*)&PyDict_Type)", py_object_type],
"set": ["((PyObject*)&PySet_Type)", py_object_type],
"frozenset": ["((PyObject*)&PyFrozenSet_Type)", py_object_type],
"slice": ["((PyObject*)&PySlice_Type)", py_object_type],
"file": ["((PyObject*)&PyFile_Type)", py_object_type],
"None": ["Py_None", py_object_type],
"False": ["Py_False", py_object_type],
"True": ["Py_True", py_object_type],
}
const_counter = 1 # As a temporary solution for compiling code in pxds
class ModuleScope(Scope):
# module_name string Python name of the module
# module_cname string C name of Python module object
# #module_dict_cname string C name of module dict object
# method_table_cname string C name of method table
# doc string Module doc string
# doc_cname string C name of module doc string
# utility_code_list [UtilityCode] Queuing utility codes for forwarding to Code.py
# python_include_files [string] Standard Python headers to be included
# include_files [string] Other C headers to be included
# string_to_entry {string : Entry} Map string const to entry
# identifier_to_entry {string : Entry} Map identifier string const to entry
# context Context
# parent_module Scope Parent in the import namespace
# module_entries {string : Entry} For cimport statements
# type_names {string : 1} Set of type names (used during parsing)
# included_files [string] Cython sources included with 'include'
# pxd_file_loaded boolean Corresponding .pxd file has been processed
# cimported_modules [ModuleScope] Modules imported with cimport
# types_imported {PyrexType : 1} Set of types for which import code generated
# has_import_star boolean Module contains import *
# cpp boolean Compiling a C++ file
is_module_scope = 1
has_import_star = 0
def __init__(self, name, parent_module, context):
self.parent_module = parent_module
outer_scope = context.find_submodule("__builtin__")
Scope.__init__(self, name, outer_scope, parent_module)
if name != "__init__":
self.module_name = name
else:
# Treat Spam/__init__.pyx specially, so that when Python loads
# Spam/__init__.so, initSpam() is defined.
self.module_name = parent_module.module_name
self.context = context
self.module_cname = Naming.module_cname
self.module_dict_cname = Naming.moddict_cname
self.method_table_cname = Naming.methtable_cname
self.doc = ""
self.doc_cname = Naming.moddoc_cname
self.utility_code_list = []
self.module_entries = {}
self.python_include_files = ["Python.h"]
self.include_files = []
self.type_names = dict(outer_scope.type_names)
self.pxd_file_loaded = 0
self.cimported_modules = []
self.types_imported = {}
self.included_files = []
self.has_extern_class = 0
self.cached_builtins = []
self.undeclared_cached_builtins = []
self.namespace_cname = self.module_cname
for name in ['__builtins__', '__name__', '__file__', '__doc__']:
self.declare_var(EncodedString(name), py_object_type, None)
def qualifying_scope(self):
return self.parent_module
def global_scope(self):
return self
def declare_builtin(self, name, pos):
if not hasattr(builtins, name) and name != 'xrange':
# 'xrange' is special cased in Code.py
if self.has_import_star:
entry = self.declare_var(name, py_object_type, pos)
return entry
elif self.outer_scope is not None:
return self.outer_scope.declare_builtin(name, pos)
else:
error(pos, "undeclared name not builtin: %s"%name)
if Options.cache_builtins:
for entry in self.cached_builtins:
if entry.name == name:
return entry
entry = self.declare(None, None, py_object_type, pos, 'private')
if Options.cache_builtins:
entry.is_builtin = 1
entry.is_const = 1
entry.name = name
entry.cname = Naming.builtin_prefix + name
self.cached_builtins.append(entry)
self.undeclared_cached_builtins.append(entry)
else:
entry.is_builtin = 1
return entry
def find_module(self, module_name, pos):
# Find a module in the import namespace, interpreting
# relative imports relative to this module's parent.
# Finds and parses the module's .pxd file if the module
# has not been referenced before.
return self.global_scope().context.find_module(
module_name, relative_to = self.parent_module, pos = pos)
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.
scope = self.lookup_submodule(name)
if not scope:
scope = ModuleScope(name,
parent_module = self, context = self.context)
self.module_entries[name] = scope
return scope
def lookup_submodule(self, name):
# Return scope for submodule of this module, or None.
return self.module_entries.get(name, None)
def add_include_file(self, filename):
if filename not in self.python_include_files \
and filename not in self.include_files:
self.include_files.append(filename)
def add_imported_module(self, scope):
if scope not in self.cimported_modules:
for filename in scope.include_files:
self.add_include_file(filename)
self.cimported_modules.append(scope)
for m in scope.cimported_modules:
self.add_imported_module(m)
def add_imported_entry(self, name, entry, pos):
if entry not in self.entries:
self.entries[name] = entry
else:
warning(pos, "'%s' redeclared " % name, 0)
def declare_module(self, name, scope, pos):
# Declare a cimported module. This is represented as a
# Python module-level variable entry with a module
# scope attached to it. Reports an error and returns
# None if previously declared as something else.
entry = self.lookup_here(name)
if entry:
if entry.is_pyglobal and entry.as_module is scope:
return entry # Already declared as the same module
if not (entry.is_pyglobal and not entry.as_module):
# SAGE -- I put this here so Pyrex
# cimport's work across directories.
# Currently it tries to multiply define
# every module appearing in an import list.
# It shouldn't be an error for a module
# name to appear again, and indeed the generated
# code compiles fine.
return entry
warning(pos, "'%s' redeclared " % name, 0)
return None
else:
entry = self.declare_var(name, py_object_type, pos)
entry.as_module = scope
self.add_imported_module(scope)
return entry
def declare_var(self, name, type, pos,
cname = None, visibility = 'private', is_cdef = 0):
# Add an entry for a global variable. If it is a Python
# object type, and not declared with cdef, it will live
# in the module dictionary, otherwise it will be a C
# global variable.
entry = Scope.declare_var(self, name, type, pos,
cname, visibility, is_cdef)
if not visibility in ('private', 'public', 'extern'):
error(pos, "Module-level variable cannot be declared %s" % visibility)
if not is_cdef:
if type is unspecified_type:
type = py_object_type
if not (type.is_pyobject and not type.is_extension_type):
raise InternalError(
"Non-cdef global variable is not a generic Python object")
entry.is_pyglobal = 1
else:
entry.is_cglobal = 1
if entry.type.is_pyobject:
entry.init = 0
self.var_entries.append(entry)
return entry
def declare_global(self, name, pos):
entry = self.lookup_here(name)
if not entry:
self.declare_var(name, py_object_type, pos)
def use_utility_code(self, new_code):
if new_code is not None:
self.utility_code_list.append(new_code)
def declare_c_class(self, name, pos, defining = 0, implementing = 0,
module_name = None, base_type = None, objstruct_cname = None,
typeobj_cname = None, visibility = 'private', typedef_flag = 0, api = 0,
buffer_defaults = None):
# 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.
if typedef_flag and visibility != 'extern':
if visibility != 'public':
warning(pos, "ctypedef only valid for public and extern classes", 2)
objtypedef_cname = objstruct_cname
typedef_flag = 0
else:
objtypedef_cname = None
#
# Look for previous declaration as a type
#
entry = self.lookup_here(name)
if entry:
type = entry.type
if not (entry.is_type and type.is_extension_type):
entry = None # Will cause redeclaration and produce an error
else:
scope = type.scope
if typedef_flag and (not scope or scope.defined):
self.check_previous_typedef_flag(entry, typedef_flag, pos)
if (scope and scope.defined) or (base_type and type.base_type):
if base_type and base_type is not type.base_type:
error(pos, "Base type does not match previous declaration")
if base_type and not type.base_type:
type.base_type = base_type
#
# Make a new entry if needed
#
if not entry:
type = PyrexTypes.PyExtensionType(name, typedef_flag, base_type, visibility == 'extern')
type.pos = pos
type.buffer_defaults = buffer_defaults
if objtypedef_cname is not None:
type.objtypedef_cname = objtypedef_cname
if visibility == 'extern':
type.module_name = module_name
else:
type.module_name = self.qualified_name
type.typeptr_cname = self.mangle(Naming.typeptr_prefix, name)
entry = self.declare_type(name, type, pos, visibility = visibility,
defining = 0)
entry.is_cclass = True
if objstruct_cname:
type.objstruct_cname = objstruct_cname
elif not entry.in_cinclude:
type.objstruct_cname = self.mangle(Naming.objstruct_prefix, name)
else:
error(entry.pos,
"Object name required for 'public' or 'extern' C class")
self.attach_var_entry_to_c_class(entry)
self.c_class_entries.append(entry)
#
# Check for re-definition and create scope if needed
#
if not type.scope:
if defining or implementing:
scope = CClassScope(name = name, outer_scope = self,
visibility = visibility)
if base_type and base_type.scope:
scope.declare_inherited_c_attributes(base_type.scope)
type.set_scope(scope)
self.type_entries.append(entry)
else:
self.check_for_illegal_incomplete_ctypedef(typedef_flag, pos)
else:
if defining and type.scope.defined:
error(pos, "C class '%s' already defined" % name)
elif implementing and type.scope.implemented:
error(pos, "C class '%s' already implemented" % name)
#
# Fill in options, checking for compatibility with any previous declaration
#
if defining:
entry.defined_in_pxd = 1
if implementing: # So that filenames in runtime exceptions refer to
entry.pos = pos # the .pyx file and not the .pxd file
if visibility != 'private' and entry.visibility != visibility:
error(pos, "Class '%s' previously declared as '%s'"
% (name, entry.visibility))
if api:
entry.api = 1
if objstruct_cname:
if type.objstruct_cname and type.objstruct_cname != objstruct_cname:
error(pos, "Object struct name differs from previous declaration")
type.objstruct_cname = objstruct_cname
if typeobj_cname:
if type.typeobj_cname and type.typeobj_cname != typeobj_cname:
error(pos, "Type object name differs from previous declaration")
type.typeobj_cname = typeobj_cname
#
# Return new or existing entry
#
return entry
def check_for_illegal_incomplete_ctypedef(self, typedef_flag, pos):
if typedef_flag and not self.in_cinclude:
error(pos, "Forward-referenced type must use 'cdef', not 'ctypedef'")
def allocate_vtable_names(self, entry):
# If extension type has a vtable, allocate vtable struct and
# slot names for it.
type = entry.type
if type.base_type and type.base_type.vtabslot_cname:
#print "...allocating vtabslot_cname because base type has one" ###
type.vtabslot_cname = "%s.%s" % (
Naming.obj_base_cname, type.base_type.vtabslot_cname)
elif type.scope and type.scope.cfunc_entries:
#print "...allocating vtabslot_cname because there are C methods" ###
type.vtabslot_cname = Naming.vtabslot_cname
if type.vtabslot_cname:
#print "...allocating other vtable related cnames" ###
type.vtabstruct_cname = self.mangle(Naming.vtabstruct_prefix, entry.name)
type.vtabptr_cname = self.mangle(Naming.vtabptr_prefix, entry.name)
def check_c_classes_pxd(self):
# Performs post-analysis checking and finishing up of extension types
# being implemented in this module. This is called only for the .pxd.
#
# Checks all extension types declared in this scope to
# make sure that:
#
# * The extension type is fully declared
#
# Also allocates a name for the vtable if needed.
#
for entry in self.c_class_entries:
# Check defined
if not entry.type.scope:
error(entry.pos, "C class '%s' is declared but not defined" % entry.name)
def check_c_classes(self):
# Performs post-analysis checking and finishing up of extension types
# being implemented in this module. This is called only for the main
# .pyx file scope, not for cimported .pxd scopes.
#
# Checks all extension types declared in this scope to
# make sure that:
#
# * The extension type is implemented
# * All required object and type names have been specified or generated
# * All non-inherited C methods are implemented
#
# Also allocates a name for the vtable if needed.
#
debug_check_c_classes = 0
if debug_check_c_classes:
print("Scope.check_c_classes: checking scope " + self.qualified_name)
for entry in self.c_class_entries:
if debug_check_c_classes:
print("...entry %s %s" % (entry.name, entry))
print("......type = ", entry.type)
print("......visibility = ", entry.visibility)
type = entry.type
name = entry.name
visibility = entry.visibility
# Check defined
if not type.scope:
error(entry.pos, "C class '%s' is declared but not defined" % name)
# Generate typeobj_cname
if visibility != 'extern' and not type.typeobj_cname:
type.typeobj_cname = self.mangle(Naming.typeobj_prefix, name)
## Generate typeptr_cname
#type.typeptr_cname = self.mangle(Naming.typeptr_prefix, name)
# Check C methods defined
if type.scope:
for method_entry in type.scope.cfunc_entries:
if not method_entry.is_inherited and not method_entry.func_cname:
error(method_entry.pos, "C method '%s' is declared but not defined" %
method_entry.name)
# Allocate vtable name if necessary
if type.vtabslot_cname:
#print "ModuleScope.check_c_classes: allocating vtable cname for", self ###
type.vtable_cname = self.mangle(Naming.vtable_prefix, entry.name)
def check_c_functions(self):
# Performs post-analysis checking making sure all
# defined c functions are actually implemented.
for name, entry in self.entries.items():
if entry.is_cfunction:
if (entry.defined_in_pxd
and entry.scope is self
and entry.visibility != 'extern'
and not entry.in_cinclude
and not entry.is_implemented):
error(entry.pos, "Non-extern C function '%s' declared but not defined" % name)
def attach_var_entry_to_c_class(self, entry):
# The name of an extension class has to serve as both a type
# name and a variable name holding the type object. It is
# represented in the symbol table by a type entry with a
# variable entry attached to it. For the variable entry,
# we use a read-only C global variable whose name is an
# expression that refers to the type object.
import Builtin
var_entry = Entry(name = entry.name,
type = Builtin.type_type,
pos = entry.pos,
cname = "((PyObject*)%s)" % entry.type.typeptr_cname)
var_entry.is_variable = 1
var_entry.is_cglobal = 1
var_entry.is_readonly = 1
entry.as_variable = var_entry
def is_cpp(self):
return self.cpp
def infer_types(self):
from TypeInference import PyObjectTypeInferer
PyObjectTypeInferer().infer_types(self)
class LocalScope(Scope):
def __init__(self, name, outer_scope, parent_scope = None):
if parent_scope is None:
parent_scope = outer_scope
Scope.__init__(self, name, outer_scope, parent_scope)
def mangle(self, prefix, name):
return prefix + name
def declare_arg(self, name, type, pos):
# Add an entry for an argument of a function.
cname = self.mangle(Naming.var_prefix, name)
entry = self.declare(name, cname, type, pos, 'private')
entry.is_variable = 1
if type.is_pyobject:
entry.init = "0"
entry.is_arg = 1
#entry.borrowed = 1 # Not using borrowed arg refs for now
self.arg_entries.append(entry)
self.control_flow.set_state((), (name, 'source'), 'arg')
return entry
def declare_var(self, name, type, pos,
cname = None, visibility = 'private', is_cdef = 0):
# Add an entry for a local variable.
if visibility in ('public', 'readonly'):
error(pos, "Local variable cannot be declared %s" % visibility)
entry = Scope.declare_var(self, name, type, pos,
cname, visibility, is_cdef)
if type.is_pyobject and not Options.init_local_none:
entry.init = "0"
entry.init_to_none = (type.is_pyobject or type.is_unspecified) and Options.init_local_none
entry.is_local = 1
self.var_entries.append(entry)
return entry
def declare_global(self, name, pos):
# Pull entry from global scope into local scope.
if self.lookup_here(name):
warning(pos, "'%s' redeclared ", 0)
else:
entry = self.global_scope().lookup_target(name)
self.entries[name] = entry
def lookup(self, name):
# Look up name in this scope or an enclosing one.
# Return None if not found.
entry = Scope.lookup(self, name)
if entry is not None:
if entry.scope is not self and entry.scope.is_closure_scope:
# The actual c fragment for the different scopes differs
# on the outside and inside, so we make a new entry
entry.in_closure = True
# Would it be better to declare_var here?
inner_entry = Entry(entry.name, entry.cname, entry.type, entry.pos)
inner_entry.scope = self
inner_entry.is_variable = True
inner_entry.outer_entry = entry
inner_entry.from_closure = True
self.entries[name] = inner_entry
return inner_entry
return entry
def mangle_closure_cnames(self, outer_scope_cname):
for entry in self.entries.values():
if entry.from_closure:
cname = entry.outer_entry.cname
if cname.startswith(Naming.cur_scope_cname):
cname = cname[len(Naming.cur_scope_cname)+2:]
entry.cname = "%s->%s" % (outer_scope_cname, cname)
elif entry.in_closure:
entry.original_cname = entry.cname
entry.cname = "%s->%s" % (Naming.cur_scope_cname, entry.cname)
class GeneratorExpressionScope(LocalScope):
"""Scope for generator expressions and comprehensions. As opposed
to generators, these can be easily inlined in some cases, so all
we really need is a scope that holds the loop variable(s).
"""
def __init__(self, outer_scope):
name = outer_scope.global_scope().next_id(Naming.genexpr_id_ref)
LocalScope.__init__(self, name, outer_scope)
self.directives = outer_scope.directives
self.genexp_prefix = "%s%d%s" % (Naming.pyrex_prefix, len(name), name)
def mangle(self, prefix, name):
return '%s%s' % (self.genexp_prefix, self.outer_scope.mangle(self, prefix, name))
def declare_var(self, name, type, pos,
cname = None, visibility = 'private', is_cdef = True):
if type is unspecified_type:
# if the outer scope defines a type for this variable, inherit it
outer_entry = self.outer_scope.lookup(name)
if outer_entry and outer_entry.is_variable:
type = outer_entry.type # may still be 'unspecified_type' !
# the outer scope needs to generate code for the variable, but
# this scope must hold its name exclusively
cname = '%s%s' % (self.genexp_prefix, self.outer_scope.mangle(Naming.var_prefix, name))
entry = self.outer_scope.declare_var(None, type, pos, cname, visibility, is_cdef = True)
self.entries[name] = entry
return entry
class ClosureScope(LocalScope):
is_closure_scope = True
def __init__(self, name, scope_name, outer_scope):
LocalScope.__init__(self, name, outer_scope)
self.closure_cname = "%s%s" % (Naming.closure_scope_prefix, scope_name)
# def mangle_closure_cnames(self, scope_var):
# for entry in self.entries.values() + self.temp_entries:
# entry.in_closure = 1
# LocalScope.mangle_closure_cnames(self, scope_var)
# def mangle(self, prefix, name):
# return "%s->%s" % (self.cur_scope_cname, name)
# return "%s->%s" % (self.closure_cname, name)
def declare_pyfunction(self, name, pos):
# Add an entry for a Python function.
entry = self.lookup_here(name)
if entry and not entry.type.is_cfunction:
# This is legal Python, but for now may produce invalid C.
error(pos, "'%s' already declared" % name)
entry = self.declare_var(name, py_object_type, pos)
entry.signature = pyfunction_signature
self.pyfunc_entries.append(entry)
return entry
class StructOrUnionScope(Scope):
# Namespace of a C struct or union.
def __init__(self, name="?"):
Scope.__init__(self, name, None, None)
def declare_var(self, name, type, pos,
cname = None, visibility = 'private', is_cdef = 0, allow_pyobject = 0):
# Add an entry for an attribute.
if not cname:
cname = name
if visibility == 'private':
cname = c_safe_identifier(cname)
if type.is_cfunction:
type = PyrexTypes.CPtrType(type)
entry = self.declare(name, cname, type, pos, visibility)
entry.is_variable = 1
self.var_entries.append(entry)
if type.is_pyobject and not allow_pyobject:
error(pos,
"C struct/union member cannot be a Python object")
if visibility != 'private':
error(pos,
"C struct/union member cannot be declared %s" % visibility)
return entry
def declare_cfunction(self, name, type, pos,
cname = None, visibility = 'private', defining = 0,
api = 0, in_pxd = 0, modifiers = ()):
return self.declare_var(name, type, pos, cname, visibility)
class ClassScope(Scope):
# Abstract base class for namespace of
# Python class or extension type.
#
# class_name string Pyrex name of the class
# scope_prefix string Additional prefix for names
# declared in the class
# doc string or None Doc string
def __init__(self, name, outer_scope):
Scope.__init__(self, name, outer_scope, outer_scope)
self.class_name = name
self.doc = None
def add_string_const(self, value, identifier = False):
return self.outer_scope.add_string_const(value, identifier)
def lookup(self, name):
entry = Scope.lookup(self, name)
if entry:
return entry
if name == "classmethod":
# We don't want to use the builtin classmethod here 'cause it won't do the
# right thing in this scope (as the class memebers aren't still functions).
# Don't want to add a cfunction to this scope 'cause that would mess with
# the type definition, so we just return the right entry.
self.use_utility_code(classmethod_utility_code)
entry = Entry(
"classmethod",
"__Pyx_Method_ClassMethod",
PyrexTypes.CFuncType(
py_object_type,
[PyrexTypes.CFuncTypeArg("", py_object_type, None)], 0, 0))
entry.is_cfunction = 1
return entry
class PyClassScope(ClassScope):
# Namespace of a Python class.
#
# class_obj_cname string C variable holding class object
is_py_class_scope = 1
def declare_var(self, name, type, pos,
cname = None, visibility = 'private', is_cdef = 0):
if type is unspecified_type:
type = py_object_type
# Add an entry for a class attribute.
entry = Scope.declare_var(self, name, type, pos,
cname, visibility, is_cdef)
entry.is_pyglobal = 1
return entry
def add_default_value(self, type):
return self.outer_scope.add_default_value(type)
class CClassScope(ClassScope):
# Namespace of an extension type.
#
# parent_type CClassType
# #typeobj_cname string or None
# #objstruct_cname string
# method_table_cname string
# getset_table_cname string
# has_pyobject_attrs boolean Any PyObject attributes?
# property_entries [Entry]
# defined boolean Defined in .pxd file
# implemented boolean Defined in .pyx file
# inherited_var_entries [Entry] Adapted var entries from base class
is_c_class_scope = 1
def __init__(self, name, outer_scope, visibility):
ClassScope.__init__(self, name, outer_scope)
if visibility != 'extern':
self.method_table_cname = outer_scope.mangle(Naming.methtab_prefix, name)
self.getset_table_cname = outer_scope.mangle(Naming.gstab_prefix, name)
self.has_pyobject_attrs = 0
self.property_entries = []
self.inherited_var_entries = []
self.defined = 0
self.implemented = 0
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.
return self.has_pyobject_attrs or \
(self.parent_type.base_type and
self.parent_type.base_type.scope is not None and
self.parent_type.base_type.scope.needs_gc())
def declare_var(self, name, type, pos,
cname = None, visibility = 'private', is_cdef = 0):
if is_cdef:
# Add an entry for an attribute.
if self.defined:
error(pos,
"C attributes cannot be added in implementation part of"
" extension type defined in a pxd")
if get_special_method_signature(name):
error(pos,
"The name '%s' is reserved for a special method."
% name)
if not cname:
cname = name
if visibility == 'private':
cname = c_safe_identifier(cname)
if type.is_cpp_class and visibility != 'extern':
error(pos, "C++ classes not allowed as members of an extension type, use a pointer or reference instead")
entry = self.declare(name, cname, type, pos, visibility)
entry.is_variable = 1
self.var_entries.append(entry)
if type.is_pyobject:
self.has_pyobject_attrs = 1
if visibility not in ('private', 'public', 'readonly'):
error(pos,
"Attribute of extension type cannot be declared %s" % visibility)
if visibility in ('public', 'readonly'):
if name == "__weakref__":
error(pos, "Special attribute __weakref__ cannot be exposed to Python")
if not type.is_pyobject:
if (not type.create_to_py_utility_code(self) or
(visibility=='public' and not
type.create_from_py_utility_code(self))):
error(pos,
"C attribute of type '%s' cannot be accessed from Python" % type)
return entry
else:
if type is unspecified_type:
type = py_object_type
# Add an entry for a class attribute.
entry = Scope.declare_var(self, name, type, pos,
cname, visibility, is_cdef)
entry.is_member = 1
entry.is_pyglobal = 1 # xxx: is_pyglobal changes behaviour in so many places that
# I keep it in for now. is_member should be enough
# later on
self.namespace_cname = "(PyObject *)%s" % self.parent_type.typeptr_cname
return entry
def declare_pyfunction(self, name, pos):
# Add an entry for a method.
if name in ('__eq__', '__ne__', '__lt__', '__gt__', '__le__', '__ge__'):
error(pos, "Special method %s must be implemented via __richcmp__" % name)
if name == "__new__":
warning(pos, "__new__ method of extension type will change semantics "
"in a future version of Pyrex and Cython. Use __cinit__ instead.")
name = EncodedString("__cinit__")
entry = self.declare_var(name, py_object_type, pos, visibility='extern')
special_sig = get_special_method_signature(name)
if special_sig:
# Special methods get put in the method table with a particular
# signature declared in advance.
entry.signature = special_sig
entry.is_special = 1
else:
entry.signature = pymethod_signature
entry.is_special = 0
self.pyfunc_entries.append(entry)
return entry
def lookup_here(self, name):
if name == "__new__":
name = EncodedString("__cinit__")
return ClassScope.lookup_here(self, name)
def declare_cfunction(self, name, type, pos,
cname = None, visibility = 'private',
defining = 0, api = 0, in_pxd = 0, modifiers = ()):
if get_special_method_signature(name):
error(pos, "Special methods must be declared with 'def', not 'cdef'")
args = type.args
if not args:
error(pos, "C method has no self argument")
elif not self.parent_type.assignable_from(args[0].type):
error(pos, "Self argument (%s) of C method '%s' does not match parent type (%s)" %
(args[0].type, name, self.parent_type))
entry = self.lookup_here(name)
if entry:
if not entry.is_cfunction:
warning(pos, "'%s' redeclared " % name, 0)
else:
if defining and entry.func_cname:
error(pos, "'%s' already defined" % name)
#print "CClassScope.declare_cfunction: checking signature" ###
if type.same_c_signature_as(entry.type, as_cmethod = 1) and type.nogil == entry.type.nogil:
pass
elif type.compatible_signature_with(entry.type, as_cmethod = 1) and type.nogil == entry.type.nogil:
entry = self.add_cfunction(name, type, pos, cname or name, visibility='ignore', modifiers=modifiers)
defining = 1
else:
error(pos, "Signature not compatible with previous declaration")
error(entry.pos, "Previous declaration is here")
else:
if self.defined:
error(pos,
"C method '%s' not previously declared in definition part of"
" extension type" % name)
entry = self.add_cfunction(name, type, pos, cname or name,
visibility, modifiers)
if defining:
entry.func_cname = self.mangle(Naming.func_prefix, name)
return entry
def add_cfunction(self, name, type, pos, cname, visibility, modifiers):
# Add a cfunction entry without giving it a func_cname.
prev_entry = self.lookup_here(name)
entry = ClassScope.add_cfunction(self, name, type, pos, cname,
visibility, modifiers)
entry.is_cmethod = 1
entry.prev_entry = prev_entry
return entry
def declare_property(self, name, doc, pos):
entry = self.lookup_here(name)
if entry is None:
entry = self.declare(name, name, py_object_type, pos, 'private')
entry.is_property = 1
entry.doc = doc
entry.scope = PropertyScope(name,
outer_scope = self.global_scope(), parent_scope = self)
entry.scope.parent_type = self.parent_type
self.property_entries.append(entry)
return entry
def declare_inherited_c_attributes(self, base_scope):
# Declare entries for all the C attributes of an
# inherited type, with cnames modified appropriately
# to work with this type.
def adapt(cname):
return "%s.%s" % (Naming.obj_base_cname, base_entry.cname)
for base_entry in \
base_scope.inherited_var_entries + base_scope.var_entries:
entry = self.declare(base_entry.name, adapt(base_entry.cname),
base_entry.type, None, 'private')
entry.is_variable = 1
self.inherited_var_entries.append(entry)
for base_entry in base_scope.cfunc_entries:
entry = self.add_cfunction(base_entry.name, base_entry.type,
base_entry.pos, adapt(base_entry.cname),
base_entry.visibility, base_entry.func_modifiers)
entry.is_inherited = 1
class CppClassScope(Scope):
# Namespace of a C++ class.
is_cpp_class_scope = 1
default_constructor = None
def __init__(self, name, outer_scope):
Scope.__init__(self, name, outer_scope, None)
self.directives = outer_scope.directives
self.inherited_var_entries = []
def declare_var(self, name, type, pos,
cname = None, visibility = 'extern', is_cdef = 0, allow_pyobject = 0):
# Add an entry for an attribute.
if not cname:
cname = name
if type.is_cfunction:
type = PyrexTypes.CPtrType(type)
entry = self.declare(name, cname, type, pos, visibility)
entry.is_variable = 1
self.var_entries.append(entry)
if type.is_pyobject and not allow_pyobject:
error(pos,
"C++ class member cannot be a Python object")
return entry
def check_base_default_constructor(self, pos):
# Look for default constructors in all base classes.
if self.default_constructor is None:
entry = self.lookup(self.name)
if len(entry.type.base_classes) == 0:
self.default_constructor = True
return
for base_class in entry.type.base_classes:
temp_entry = base_class.scope.lookup_here("")
found = False
if temp_entry is None:
continue
for alternative in temp_entry.all_alternatives():
type = alternative.type
if type.is_ptr:
type = type.base_type
if len(type.args) == 0:
found = True
break
if not found:
self.default_constructor = temp_entry.scope.name
error(pos, "no matching function for call to " \
"%s::%s()" % (temp_entry.scope.name, temp_entry.scope.name))
elif not self.default_constructor:
error(pos, "no matching function for call to %s::%s()" %
(self.default_constructor, self.default_constructor))
def declare_cfunction(self, name, type, pos,
cname = None, visibility = 'extern', defining = 0,
api = 0, in_pxd = 0, modifiers = ()):
if name == self.name.split('::')[-1] and cname is None:
self.check_base_default_constructor(pos)
name = ''
type.return_type = self.lookup(self.name).type
prev_entry = self.lookup_here(name)
entry = self.declare_var(name, type, pos, cname, visibility)
if prev_entry:
entry.overloaded_alternatives = prev_entry.all_alternatives()
def declare_inherited_cpp_attributes(self, base_scope):
# Declare entries for all the C++ attributes of an
# inherited type, with cnames modified appropriately
# to work with this type.
for base_entry in \
base_scope.inherited_var_entries + base_scope.var_entries:
#contructor is not inherited
if base_entry.name == "":
continue
#print base_entry.name, self.entries
if base_entry.name in self.entries:
base_entry.name
entry = self.declare(base_entry.name, base_entry.cname,
base_entry.type, None, 'extern')
entry.is_variable = 1
self.inherited_var_entries.append(entry)
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, base_entry.func_modifiers)
entry.is_inherited = 1
def specialize(self, values):
scope = CppClassScope(self.name, self.outer_scope)
for entry in self.entries.values():
if entry.is_type:
scope.declare_type(entry.name,
entry.type.specialize(values),
entry.pos,
entry.cname)
else:
# scope.declare_var(entry.name,
# entry.type.specialize(values),
# entry.pos,
# entry.cname,
# entry.visibility)
for e in entry.all_alternatives():
scope.declare_cfunction(e.name,
e.type.specialize(values),
e.pos,
e.cname)
return scope
def add_include_file(self, filename):
self.outer_scope.add_include_file(filename)
class PropertyScope(Scope):
# Scope holding the __get__, __set__ and __del__ methods for
# a property of an extension type.
#
# parent_type PyExtensionType The type to which the property belongs
is_property_scope = 1
def declare_pyfunction(self, name, pos):
# Add an entry for a method.
signature = get_property_accessor_signature(name)
if signature:
entry = self.declare(name, name, py_object_type, pos, 'private')
entry.is_special = 1
entry.signature = signature
return entry
else:
error(pos, "Only __get__, __set__ and __del__ methods allowed "
"in a property declaration")
return None
# Should this go elsewhere (and then get imported)?
#------------------------------------------------------------------------------------
classmethod_utility_code = Code.UtilityCode(
proto = """
#include "descrobject.h"
static PyObject* __Pyx_Method_ClassMethod(PyObject *method); /*proto*/
""",
impl = """
static PyObject* __Pyx_Method_ClassMethod(PyObject *method) {
/* It appears that PyMethodDescr_Type is not anywhere exposed in the Python/C API */
static PyTypeObject *methoddescr_type = NULL;
if (methoddescr_type == NULL) {
PyObject *meth = __Pyx_GetAttrString((PyObject*)&PyList_Type, "append");
if (!meth) return NULL;
methoddescr_type = Py_TYPE(meth);
Py_DECREF(meth);
}
if (PyObject_TypeCheck(method, methoddescr_type)) { /* cdef classes */
PyMethodDescrObject *descr = (PyMethodDescrObject *)method;
#if PY_VERSION_HEX < 0x03020000
PyTypeObject *d_type = descr->d_type;
#else
PyTypeObject *d_type = descr->d_common.d_type;
#endif
return PyDescr_NewClassMethod(d_type, descr->d_method);
}
else if (PyMethod_Check(method)) { /* python classes */
return PyClassMethod_New(PyMethod_GET_FUNCTION(method));
}
else if (PyCFunction_Check(method)) {
return PyClassMethod_New(method);
}
PyErr_Format(PyExc_TypeError,
"Class-level classmethod() can only be called on"
"a method_descriptor or instance method.");
return NULL;
}
""")
#------------------------------------------------------------------------------------
ERR_BUF_LOCALONLY = 'Buffer types only allowed as function local variables'
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Tests/ 0000775 0000000 0000000 00000000000 11446142532 0024064 5 ustar 00root root 0000000 0000000 cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Tests/TestBuffer.py 0000664 0000000 0000000 00000007761 11446142532 0026522 0 ustar 00root root 0000000 0000000 from Cython.TestUtils import CythonTest
import Cython.Compiler.Errors as Errors
from Cython.Compiler.Nodes import *
from Cython.Compiler.ParseTreeTransforms import *
from Cython.Compiler.Buffer import *
class TestBufferParsing(CythonTest):
# First, we only test the raw parser, i.e.
# the number and contents of arguments are NOT checked.
# However "dtype"/the first positional argument is special-cased
# to parse a type argument rather than an expression
def parse(self, s):
return self.should_not_fail(lambda: self.fragment(s)).root
def not_parseable(self, expected_error, s):
e = self.should_fail(lambda: self.fragment(s), Errors.CompileError)
self.assertEqual(expected_error, e.message_only)
def test_basic(self):
t = self.parse(u"cdef object[float, 4, ndim=2, foo=foo] x")
bufnode = t.stats[0].base_type
self.assert_(isinstance(bufnode, TemplatedTypeNode))
self.assertEqual(2, len(bufnode.positional_args))
# print bufnode.dump()
# should put more here...
def test_type_pos(self):
self.parse(u"cdef object[short unsigned int, 3] x")
def test_type_keyword(self):
self.parse(u"cdef object[foo=foo, dtype=short unsigned int] x")
def test_pos_after_key(self):
self.not_parseable("Non-keyword arg following keyword arg",
u"cdef object[foo=1, 2] x")
# See also tests/error/e_bufaccess.pyx and tets/run/bufaccess.pyx
# THESE TESTS ARE NOW DISABLED, the code they test was pretty much
# refactored away
class TestBufferOptions(CythonTest):
# Tests the full parsing of the options within the brackets
def nonfatal_error(self, error):
# We're passing self as context to transform to trap this
self.error = error
self.assert_(self.expect_error)
def parse_opts(self, opts, expect_error=False):
assert opts != ""
s = u"def f():\n cdef object[%s] x" % opts
self.expect_error = expect_error
root = self.fragment(s, pipeline=[NormalizeTree(self), PostParse(self)]).root
if not expect_error:
vardef = root.stats[0].body.stats[0]
assert isinstance(vardef, CVarDefNode) # use normal assert as this is to validate the test code
buftype = vardef.base_type
self.assert_(isinstance(buftype, TemplatedTypeNode))
self.assert_(isinstance(buftype.base_type_node, CSimpleBaseTypeNode))
self.assertEqual(u"object", buftype.base_type_node.name)
return buftype
else:
self.assert_(len(root.stats[0].body.stats) == 0)
def non_parse(self, expected_err, opts):
self.parse_opts(opts, expect_error=True)
# e = self.should_fail(lambda: self.parse_opts(opts))
self.assertEqual(expected_err, self.error.message_only)
def __test_basic(self):
buf = self.parse_opts(u"unsigned short int, 3")
self.assert_(isinstance(buf.dtype_node, CSimpleBaseTypeNode))
self.assert_(buf.dtype_node.signed == 0 and buf.dtype_node.longness == -1)
self.assertEqual(3, buf.ndim)
def __test_dict(self):
buf = self.parse_opts(u"ndim=3, dtype=unsigned short int")
self.assert_(isinstance(buf.dtype_node, CSimpleBaseTypeNode))
self.assert_(buf.dtype_node.signed == 0 and buf.dtype_node.longness == -1)
self.assertEqual(3, buf.ndim)
def __test_ndim(self):
self.parse_opts(u"int, 2")
self.non_parse(ERR_BUF_NDIM, u"int, 'a'")
self.non_parse(ERR_BUF_NDIM, u"int, -34")
def __test_use_DEF(self):
t = self.fragment(u"""
DEF ndim = 3
def f():
cdef object[int, ndim] x
cdef object[ndim=ndim, dtype=int] y
""", pipeline=[NormalizeTree(self), PostParse(self)]).root
stats = t.stats[0].body.stats
self.assert_(stats[0].base_type.ndim == 3)
self.assert_(stats[1].base_type.ndim == 3)
# add exotic and impossible combinations as they come along...
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Tests/TestDecorators.py 0000664 0000000 0000000 00000001152 11446142532 0027402 0 ustar 00root root 0000000 0000000 import unittest
from Cython.TestUtils import TransformTest
from Cython.Compiler.ParseTreeTransforms import DecoratorTransform
class TestDecorator(TransformTest):
def test_decorator(self):
t = self.run_pipeline([DecoratorTransform(None)], u"""
def decorator(fun):
return fun
@decorator
def decorated():
pass
""")
self.assertCode(u"""
def decorator(fun):
return fun
def decorated():
pass
decorated = decorator(decorated)
""", t)
if __name__ == '__main__':
unittest.main()
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Tests/TestParseTreeTransforms.py 0000664 0000000 0000000 00000007004 11446142532 0031250 0 ustar 00root root 0000000 0000000 from Cython.TestUtils import TransformTest
from Cython.Compiler.ParseTreeTransforms import *
from Cython.Compiler.Nodes import *
class TestNormalizeTree(TransformTest):
def test_parserbehaviour_is_what_we_coded_for(self):
t = self.fragment(u"if x: y").root
self.assertLines(u"""
(root): StatListNode
stats[0]: IfStatNode
if_clauses[0]: IfClauseNode
condition: NameNode
body: ExprStatNode
expr: NameNode
""", self.treetypes(t))
def test_wrap_singlestat(self):
t = self.run_pipeline([NormalizeTree(None)], u"if x: y")
self.assertLines(u"""
(root): StatListNode
stats[0]: IfStatNode
if_clauses[0]: IfClauseNode
condition: NameNode
body: StatListNode
stats[0]: ExprStatNode
expr: NameNode
""", self.treetypes(t))
def test_wrap_multistat(self):
t = self.run_pipeline([NormalizeTree(None)], u"""
if z:
x
y
""")
self.assertLines(u"""
(root): StatListNode
stats[0]: IfStatNode
if_clauses[0]: IfClauseNode
condition: NameNode
body: StatListNode
stats[0]: ExprStatNode
expr: NameNode
stats[1]: ExprStatNode
expr: NameNode
""", self.treetypes(t))
def test_statinexpr(self):
t = self.run_pipeline([NormalizeTree(None)], u"""
a, b = x, y
""")
self.assertLines(u"""
(root): StatListNode
stats[0]: SingleAssignmentNode
lhs: TupleNode
args[0]: NameNode
args[1]: NameNode
rhs: TupleNode
args[0]: NameNode
args[1]: NameNode
""", self.treetypes(t))
def test_wrap_offagain(self):
t = self.run_pipeline([NormalizeTree(None)], u"""
x
y
if z:
x
""")
self.assertLines(u"""
(root): StatListNode
stats[0]: ExprStatNode
expr: NameNode
stats[1]: ExprStatNode
expr: NameNode
stats[2]: IfStatNode
if_clauses[0]: IfClauseNode
condition: NameNode
body: StatListNode
stats[0]: ExprStatNode
expr: NameNode
""", self.treetypes(t))
def test_pass_eliminated(self):
t = self.run_pipeline([NormalizeTree(None)], u"pass")
self.assert_(len(t.stats) == 0)
class TestWithTransform(object): # (TransformTest): # Disabled!
def test_simplified(self):
t = self.run_pipeline([WithTransform(None)], u"""
with x:
y = z ** 3
""")
self.assertCode(u"""
$0_0 = x
$0_2 = $0_0.__exit__
$0_0.__enter__()
$0_1 = True
try:
try:
$1_0 = None
y = z ** 3
except:
$0_1 = False
if (not $0_2($1_0)):
raise
finally:
if $0_1:
$0_2(None, None, None)
""", t)
def test_basic(self):
t = self.run_pipeline([WithTransform(None)], u"""
with x as y:
y = z ** 3
""")
self.assertCode(u"""
$0_0 = x
$0_2 = $0_0.__exit__
$0_3 = $0_0.__enter__()
$0_1 = True
try:
try:
$1_0 = None
y = $0_3
y = z ** 3
except:
$0_1 = False
if (not $0_2($1_0)):
raise
finally:
if $0_1:
$0_2(None, None, None)
""", t)
if __name__ == "__main__":
import unittest
unittest.main()
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Tests/TestTreeFragment.py 0000664 0000000 0000000 00000004323 11446142532 0027663 0 ustar 00root root 0000000 0000000 from Cython.TestUtils import CythonTest
from Cython.Compiler.TreeFragment import *
from Cython.Compiler.Nodes import *
from Cython.Compiler.UtilNodes import *
import Cython.Compiler.Naming as Naming
class TestTreeFragments(CythonTest):
def test_basic(self):
F = self.fragment(u"x = 4")
T = F.copy()
self.assertCode(u"x = 4", T)
def test_copy_is_taken(self):
F = self.fragment(u"if True: x = 4")
T1 = F.root
T2 = F.copy()
self.assertEqual("x", T2.stats[0].if_clauses[0].body.lhs.name)
T2.stats[0].if_clauses[0].body.lhs.name = "other"
self.assertEqual("x", T1.stats[0].if_clauses[0].body.lhs.name)
def test_substitutions_are_copied(self):
T = self.fragment(u"y + y").substitute({"y": NameNode(pos=None, name="x")})
self.assertEqual("x", T.stats[0].expr.operand1.name)
self.assertEqual("x", T.stats[0].expr.operand2.name)
self.assert_(T.stats[0].expr.operand1 is not T.stats[0].expr.operand2)
def test_substitution(self):
F = self.fragment(u"x = 4")
y = NameNode(pos=None, name=u"y")
T = F.substitute({"x" : y})
self.assertCode(u"y = 4", T)
def test_exprstat(self):
F = self.fragment(u"PASS")
pass_stat = PassStatNode(pos=None)
T = F.substitute({"PASS" : pass_stat})
self.assert_(isinstance(T.stats[0], PassStatNode), T)
def test_pos_is_transferred(self):
F = self.fragment(u"""
x = y
x = u * v ** w
""")
T = F.substitute({"v" : NameNode(pos=None, name="a")})
v = F.root.stats[1].rhs.operand2.operand1
a = T.stats[1].rhs.operand2.operand1
self.assertEquals(v.pos, a.pos)
def test_temps(self):
TemplateTransform.temp_name_counter = 0
F = self.fragment(u"""
TMP
x = TMP
""")
T = F.substitute(temps=[u"TMP"])
s = T.stats
self.assert_(s[0].expr.name == "__tmpvar_1")
# self.assert_(isinstance(s[0].expr, TempRefNode))
# self.assert_(isinstance(s[1].rhs, TempRefNode))
# self.assert_(s[0].expr.handle is s[1].rhs.handle)
if __name__ == "__main__":
import unittest
unittest.main()
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Tests/TestTreePath.py 0000664 0000000 0000000 00000010262 11446142532 0027013 0 ustar 00root root 0000000 0000000 import unittest
from Cython.Compiler.Visitor import PrintTree
from Cython.TestUtils import TransformTest
from Cython.Compiler.TreePath import find_first, find_all
from Cython.Compiler import Nodes, ExprNodes
class TestTreePath(TransformTest):
_tree = None
def _build_tree(self):
if self._tree is None:
self._tree = self.run_pipeline([], u"""
def decorator(fun): # DefNode
return fun # ReturnStatNode, NameNode
@decorator # NameNode
def decorated(): # DefNode
pass
""")
return self._tree
def test_node_path(self):
t = self._build_tree()
self.assertEquals(2, len(find_all(t, "//DefNode")))
self.assertEquals(2, len(find_all(t, "//NameNode")))
self.assertEquals(1, len(find_all(t, "//ReturnStatNode")))
self.assertEquals(1, len(find_all(t, "//DefNode//ReturnStatNode")))
def test_node_path_star(self):
t = self._build_tree()
self.assertEquals(10, len(find_all(t, "//*")))
self.assertEquals(8, len(find_all(t, "//DefNode//*")))
self.assertEquals(0, len(find_all(t, "//NameNode//*")))
def test_node_path_attribute(self):
t = self._build_tree()
self.assertEquals(2, len(find_all(t, "//NameNode/@name")))
self.assertEquals(['fun', 'decorator'], find_all(t, "//NameNode/@name"))
def test_node_path_attribute_dotted(self):
t = self._build_tree()
self.assertEquals(1, len(find_all(t, "//ReturnStatNode/@value.name")))
self.assertEquals(['fun'], find_all(t, "//ReturnStatNode/@value.name"))
def test_node_path_child(self):
t = self._build_tree()
self.assertEquals(1, len(find_all(t, "//DefNode/ReturnStatNode/NameNode")))
self.assertEquals(1, len(find_all(t, "//ReturnStatNode/NameNode")))
def test_node_path_node_predicate(self):
t = self._build_tree()
self.assertEquals(0, len(find_all(t, "//DefNode[.//ForInStatNode]")))
self.assertEquals(2, len(find_all(t, "//DefNode[.//NameNode]")))
self.assertEquals(1, len(find_all(t, "//ReturnStatNode[./NameNode]")))
self.assertEquals(Nodes.ReturnStatNode,
type(find_first(t, "//ReturnStatNode[./NameNode]")))
def test_node_path_node_predicate_step(self):
t = self._build_tree()
self.assertEquals(2, len(find_all(t, "//DefNode[.//NameNode]")))
self.assertEquals(8, len(find_all(t, "//DefNode[.//NameNode]//*")))
self.assertEquals(1, len(find_all(t, "//DefNode[.//NameNode]//ReturnStatNode")))
self.assertEquals(Nodes.ReturnStatNode,
type(find_first(t, "//DefNode[.//NameNode]//ReturnStatNode")))
def test_node_path_attribute_exists(self):
t = self._build_tree()
self.assertEquals(2, len(find_all(t, "//NameNode[@name]")))
self.assertEquals(ExprNodes.NameNode,
type(find_first(t, "//NameNode[@name]")))
def test_node_path_attribute_exists_not(self):
t = self._build_tree()
self.assertEquals(0, len(find_all(t, "//NameNode[not(@name)]")))
self.assertEquals(2, len(find_all(t, "//NameNode[not(@honking)]")))
def test_node_path_and(self):
t = self._build_tree()
self.assertEquals(1, len(find_all(t, "//DefNode[.//ReturnStatNode and .//NameNode]")))
self.assertEquals(0, len(find_all(t, "//NameNode[@honking and @name]")))
self.assertEquals(0, len(find_all(t, "//NameNode[@name and @honking]")))
self.assertEquals(2, len(find_all(t, "//DefNode[.//NameNode[@name] and @name]")))
def test_node_path_attribute_string_predicate(self):
t = self._build_tree()
self.assertEquals(1, len(find_all(t, "//NameNode[@name = 'decorator']")))
def test_node_path_recursive_predicate(self):
t = self._build_tree()
self.assertEquals(2, len(find_all(t, "//DefNode[.//NameNode[@name]]")))
self.assertEquals(1, len(find_all(t, "//DefNode[.//NameNode[@name = 'decorator']]")))
self.assertEquals(1, len(find_all(t, "//DefNode[.//ReturnStatNode[./NameNode[@name = 'fun']]/NameNode]")))
if __name__ == '__main__':
unittest.main()
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Tests/__init__.py 0000664 0000000 0000000 00000000007 11446142532 0026172 0 ustar 00root root 0000000 0000000 #empty
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/TreeFragment.py 0000664 0000000 0000000 00000017672 11446142532 0025734 0 ustar 00root root 0000000 0000000 #
# TreeFragments - parsing of strings to trees
#
import re
from StringIO import StringIO
from Scanning import PyrexScanner, StringSourceDescriptor
from Symtab import BuiltinScope, ModuleScope
import Symtab
import PyrexTypes
from Visitor import VisitorTransform
from Nodes import Node, StatListNode
from ExprNodes import NameNode
import Parsing
import Main
import UtilNodes
"""
Support for parsing strings into code trees.
"""
class StringParseContext(Main.Context):
def __init__(self, include_directories, name):
Main.Context.__init__(self, include_directories, {})
self.module_name = name
def find_module(self, module_name, relative_to = None, pos = None, need_pxd = 1):
if module_name != self.module_name:
raise AssertionError("Not yet supporting any cimports/includes from string code snippets")
return ModuleScope(module_name, parent_module = None, context = self)
def parse_from_strings(name, code, pxds={}, level=None, initial_pos=None):
"""
Utility method to parse a (unicode) string of code. This is mostly
used for internal Cython compiler purposes (creating code snippets
that transforms should emit, as well as unit testing).
code - a unicode string containing Cython (module-level) code
name - a descriptive name for the code source (to use in error messages etc.)
"""
# Since source files carry an encoding, it makes sense in this context
# 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"
encoding = "UTF-8"
module_name = name
if initial_pos is None:
initial_pos = (name, 1, 0)
code_source = StringSourceDescriptor(name, code)
context = StringParseContext([], name)
scope = context.find_module(module_name, pos = initial_pos, need_pxd = 0)
buf = StringIO(code)
scanner = PyrexScanner(buf, code_source, source_encoding = encoding,
scope = scope, context = context, initial_pos = initial_pos)
if level is None:
tree = Parsing.p_module(scanner, 0, module_name)
else:
tree = Parsing.p_code(scanner, level=level)
return tree
class TreeCopier(VisitorTransform):
def visit_Node(self, node):
if node is None:
return node
else:
c = node.clone_node()
self.visitchildren(c)
return c
class ApplyPositionAndCopy(TreeCopier):
def __init__(self, pos):
super(ApplyPositionAndCopy, self).__init__()
self.pos = pos
def visit_Node(self, node):
copy = super(ApplyPositionAndCopy, self).visit_Node(node)
copy.pos = self.pos
return copy
class TemplateTransform(VisitorTransform):
"""
Makes a copy of a template tree while doing substitutions.
A dictionary "substitutions" should be passed in when calling
the transform; mapping names to replacement nodes. Then replacement
happens like this:
- If an ExprStatNode contains a single NameNode, whose name is
a key in the substitutions dictionary, the ExprStatNode is
replaced with a copy of the tree given in the dictionary.
It is the responsibility of the caller that the replacement
node is a valid statement.
- If a single NameNode is otherwise encountered, it is replaced
if its name is listed in the substitutions dictionary in the
same way. It is the responsibility of the caller to make sure
that the replacement nodes is a valid expression.
Also a list "temps" should be passed. Any names listed will
be transformed into anonymous, temporary names.
Currently supported for tempnames is:
NameNode
(various function and class definition nodes etc. should be added to this)
Each replacement node gets the position of the substituted node
recursively applied to every member node.
"""
temp_name_counter = 0
def __call__(self, node, substitutions, temps, pos):
self.substitutions = substitutions
self.pos = pos
tempmap = {}
temphandles = []
for temp in temps:
TemplateTransform.temp_name_counter += 1
handle = "__tmpvar_%d" % TemplateTransform.temp_name_counter
# handle = UtilNodes.TempHandle(PyrexTypes.py_object_type)
tempmap[temp] = handle
# temphandles.append(handle)
self.tempmap = tempmap
result = super(TemplateTransform, self).__call__(node)
# if temps:
# result = UtilNodes.TempsBlockNode(self.get_pos(node),
# temps=temphandles,
# body=result)
return result
def get_pos(self, node):
if self.pos:
return self.pos
else:
return node.pos
def visit_Node(self, node):
if node is None:
return None
else:
c = node.clone_node()
if self.pos is not None:
c.pos = self.pos
self.visitchildren(c)
return c
def try_substitution(self, node, key):
sub = self.substitutions.get(key)
if sub is not None:
pos = self.pos
if pos is None: pos = node.pos
return ApplyPositionAndCopy(pos)(sub)
else:
return self.visit_Node(node) # make copy as usual
def visit_NameNode(self, node):
temphandle = self.tempmap.get(node.name)
if temphandle:
return NameNode(pos=node.pos, name=temphandle)
# Replace name with temporary
#return temphandle.ref(self.get_pos(node))
else:
return self.try_substitution(node, node.name)
def visit_ExprStatNode(self, node):
# If an expression-as-statement consists of only a replaceable
# NameNode, we replace the entire statement, not only the NameNode
if isinstance(node.expr, NameNode):
return self.try_substitution(node, node.expr.name)
else:
return self.visit_Node(node)
def copy_code_tree(node):
return TreeCopier()(node)
INDENT_RE = re.compile(ur"^ *")
def strip_common_indent(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""]
minindent = min([len(INDENT_RE.match(x).group(0)) for x in lines])
lines = [x[minindent:] for x in lines]
return lines
class TreeFragment(object):
def __init__(self, code, name="(tree fragment)", pxds={}, temps=[], pipeline=[], level=None, initial_pos=None):
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.iteritems():
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:
t = t.body # Make sure a StatListNode is at the top
if not isinstance(t, StatListNode):
t = StatListNode(pos=mod.pos, stats=[t])
for transform in pipeline:
t = transform(t)
self.root = t
elif isinstance(code, Node):
if pxds != {}: raise NotImplementedError()
self.root = code
else:
raise ValueError("Unrecognized code format (accepts unicode and Node)")
self.temps = temps
def copy(self):
return copy_code_tree(self.root)
def substitute(self, nodes={}, temps=[], pos = None):
return TemplateTransform()(self.root,
substitutions = nodes,
temps = self.temps + temps, pos = pos)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/TreePath.py 0000664 0000000 0000000 00000016612 11446142532 0025056 0 ustar 00root root 0000000 0000000 """
A simple XPath-like language for tree traversal.
This works by creating a filter chain of generator functions. Each
function selects a part of the expression, e.g. a child node, a
specific descendant or a node that holds an attribute.
"""
import re
import sys
path_tokenizer = re.compile(
"("
"'[^']*'|\"[^\"]*\"|"
"//?|"
"\(\)|"
"==?|"
"[/.*\[\]\(\)@])|"
"([^/\[\]\(\)@=\s]+)|"
"\s+"
).findall
def iterchildren(node, attr_name):
# returns an iterable of all child nodes of that name
child = getattr(node, attr_name)
if child is not None:
if type(child) is list:
return child
else:
return [child]
else:
return ()
def _get_first_or_none(it):
try:
try:
_next = it.next
except AttributeError:
return next(it)
else:
return _next()
except StopIteration:
return None
def type_name(node):
return node.__class__.__name__.split('.')[-1]
def parse_func(next, token):
name = token[1]
token = next()
if token[0] != '(':
raise ValueError("Expected '(' after function name '%s'" % name)
predicate = handle_predicate(next, token)
return name, predicate
def handle_func_not(next, token):
"""
not(...)
"""
name, predicate = parse_func(next, token)
def select(result):
for node in result:
if _get_first_or_none(predicate([node])) is None:
yield node
return select
def handle_name(next, token):
"""
/NodeName/
or
func(...)
"""
name = token[1]
if name in functions:
return functions[name](next, token)
def select(result):
for node in result:
for attr_name in node.child_attrs:
for child in iterchildren(node, attr_name):
if type_name(child) == name:
yield child
return select
def handle_star(next, token):
"""
/*/
"""
def select(result):
for node in result:
for name in node.child_attrs:
for child in iterchildren(node, name):
yield child
return select
def handle_dot(next, token):
"""
/./
"""
def select(result):
return result
return select
def handle_descendants(next, token):
"""
//...
"""
token = next()
if token[0] == "*":
def iter_recursive(node):
for name in node.child_attrs:
for child in iterchildren(node, name):
yield child
for c in iter_recursive(child):
yield c
elif not token[0]:
node_name = token[1]
def iter_recursive(node):
for name in node.child_attrs:
for child in iterchildren(node, name):
if type_name(child) == node_name:
yield child
for c in iter_recursive(child):
yield c
else:
raise ValueError("Expected node name after '//'")
def select(result):
for node in result:
for child in iter_recursive(node):
yield child
return select
def handle_attribute(next, token):
token = next()
if token[0]:
raise ValueError("Expected attribute name")
name = token[1]
value = None
try:
token = next()
except StopIteration:
pass
else:
if token[0] == '=':
value = parse_path_value(next)
if sys.version_info >= (2,6) or (sys.version_info >= (2,4) and '.' not in name):
import operator
readattr = operator.attrgetter(name)
else:
name_path = name.split('.')
def readattr(node):
attr_value = node
for attr in name_path:
attr_value = getattr(attr_value, attr)
return attr_value
if value is None:
def select(result):
for node in result:
try:
attr_value = readattr(node)
except AttributeError:
continue
if attr_value is not None:
yield attr_value
else:
def select(result):
for node in result:
try:
attr_value = readattr(node)
except AttributeError:
continue
if attr_value == value:
yield attr_value
return select
def parse_path_value(next):
token = next()
value = token[0]
if value:
if value[:1] == "'" or value[:1] == '"':
return value[1:-1]
try:
return int(value)
except ValueError:
pass
else:
name = token[1].lower()
if name == 'true':
return True
elif name == 'false':
return False
raise ValueError("Invalid attribute predicate: '%s'" % value)
def handle_predicate(next, token):
token = next()
selector = []
while token[0] != ']':
selector.append( operations[token[0]](next, token) )
try:
token = next()
except StopIteration:
break
else:
if token[0] == "/":
token = next()
if not token[0] and token[1] == 'and':
return logical_and(selector, handle_predicate(next, token))
def select(result):
for node in result:
subresult = iter((node,))
for select in selector:
subresult = select(subresult)
predicate_result = _get_first_or_none(subresult)
if predicate_result is not None:
yield node
return select
def logical_and(lhs_selects, rhs_select):
def select(result):
for node in result:
subresult = iter((node,))
for select in lhs_selects:
subresult = select(subresult)
predicate_result = _get_first_or_none(subresult)
subresult = iter((node,))
if predicate_result is not None:
for result_node in rhs_select(subresult):
yield node
return select
operations = {
"@": handle_attribute,
"": handle_name,
"*": handle_star,
".": handle_dot,
"//": handle_descendants,
"[": handle_predicate,
}
functions = {
'not' : handle_func_not
}
def _build_path_iterator(path):
# parse pattern
stream = iter([ (special,text)
for (special,text) in path_tokenizer(path)
if special or text ])
try:
_next = stream.next
except AttributeError:
# Python 3
def _next():
return next(stream)
token = _next()
selector = []
while 1:
try:
selector.append(operations[token[0]](_next, token))
except StopIteration:
raise ValueError("invalid path")
try:
token = _next()
if token[0] == "/":
token = _next()
except StopIteration:
break
return selector
# main module API
def iterfind(node, path):
selector_chain = _build_path_iterator(path)
result = iter((node,))
for select in selector_chain:
result = select(result)
return result
def find_first(node, path):
return _get_first_or_none(iterfind(node, path))
def find_all(node, path):
return list(iterfind(node, path))
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/TypeInference.py 0000664 0000000 0000000 00000033747 11446142532 0026112 0 ustar 00root root 0000000 0000000 from Errors import error, warning, message, warn_once, InternalError
import ExprNodes
import Nodes
import Builtin
import PyrexTypes
from Cython import Utils
from PyrexTypes import py_object_type, unspecified_type
from Visitor import CythonTransform
try:
set
except NameError:
# Python 2.3
from sets import Set as set
class TypedExprNode(ExprNodes.ExprNode):
# Used for declaring assignments of a specified type whithout a known entry.
def __init__(self, type):
self.type = type
object_expr = TypedExprNode(py_object_type)
class MarkAssignments(CythonTransform):
def mark_assignment(self, lhs, rhs):
if isinstance(lhs, (ExprNodes.NameNode, Nodes.PyArgDeclNode)):
if lhs.entry is None:
# TODO: This shouldn't happen...
return
lhs.entry.assignments.append(rhs)
elif isinstance(lhs, ExprNodes.SequenceNode):
for arg in lhs.args:
self.mark_assignment(arg, object_expr)
else:
# Could use this info to infer cdef class attributes...
pass
def visit_SingleAssignmentNode(self, node):
self.mark_assignment(node.lhs, node.rhs)
self.visitchildren(node)
return node
def visit_CascadedAssignmentNode(self, node):
for lhs in node.lhs_list:
self.mark_assignment(lhs, node.rhs)
self.visitchildren(node)
return node
def visit_InPlaceAssignmentNode(self, node):
self.mark_assignment(node.lhs, node.create_binop_node())
self.visitchildren(node)
return node
def visit_ForInStatNode(self, node):
# TODO: Remove redundancy with range optimization...
is_special = False
sequence = node.iterator.sequence
if isinstance(sequence, ExprNodes.SimpleCallNode):
function = sequence.function
if sequence.self is None and function.is_name:
if function.name in ('range', 'xrange'):
is_special = True
for arg in sequence.args[:2]:
self.mark_assignment(node.target, arg)
if len(sequence.args) > 2:
self.mark_assignment(
node.target,
ExprNodes.binop_node(node.pos,
'+',
sequence.args[0],
sequence.args[2]))
if not is_special:
# A for-loop basically translates to subsequent calls to
# __getitem__(), so using an IndexNode here allows us to
# naturally infer the base type of pointers, C arrays,
# Python strings, etc., while correctly falling back to an
# object type when the base type cannot be handled.
self.mark_assignment(node.target, ExprNodes.IndexNode(
node.pos,
base = sequence,
index = ExprNodes.IntNode(node.pos, value = '0')))
self.visitchildren(node)
return node
def visit_ForFromStatNode(self, node):
self.mark_assignment(node.target, node.bound1)
if node.step is not None:
self.mark_assignment(node.target,
ExprNodes.binop_node(node.pos,
'+',
node.bound1,
node.step))
self.visitchildren(node)
return node
def visit_ExceptClauseNode(self, node):
if node.target is not None:
self.mark_assignment(node.target, object_expr)
self.visitchildren(node)
return node
def visit_FromCImportStatNode(self, node):
pass # Can't be assigned to...
def visit_FromImportStatNode(self, node):
for name, target in node.items:
if name != "*":
self.mark_assignment(target, object_expr)
self.visitchildren(node)
return node
def visit_DefNode(self, node):
# use fake expressions with the right result type
if node.star_arg:
self.mark_assignment(
node.star_arg, TypedExprNode(Builtin.tuple_type))
if node.starstar_arg:
self.mark_assignment(
node.starstar_arg, TypedExprNode(Builtin.dict_type))
self.visitchildren(node)
return node
class MarkOverflowingArithmetic(CythonTransform):
# It may be possible to integrate this with the above for
# performance improvements (though likely not worth it).
might_overflow = False
def __call__(self, root):
self.env_stack = []
self.env = root.scope
return super(MarkOverflowingArithmetic, self).__call__(root)
def visit_safe_node(self, node):
self.might_overflow, saved = False, self.might_overflow
self.visitchildren(node)
self.might_overflow = saved
return node
def visit_neutral_node(self, node):
self.visitchildren(node)
return node
def visit_dangerous_node(self, node):
self.might_overflow, saved = True, self.might_overflow
self.visitchildren(node)
self.might_overflow = saved
return node
def visit_FuncDefNode(self, node):
self.env_stack.append(self.env)
self.env = node.local_scope
self.visit_safe_node(node)
self.env = self.env_stack.pop()
return node
def visit_NameNode(self, node):
if self.might_overflow:
entry = node.entry or self.env.lookup(node.name)
if entry:
entry.might_overflow = True
return node
def visit_BinopNode(self, node):
if node.operator in '&|^':
return self.visit_neutral_node(node)
else:
return self.visit_dangerous_node(node)
visit_UnopNode = visit_neutral_node
visit_UnaryMinusNode = visit_dangerous_node
visit_InPlaceAssignmentNode = visit_dangerous_node
visit_Node = visit_safe_node
def visit_assignment(self, lhs, rhs):
if (isinstance(rhs, ExprNodes.IntNode)
and isinstance(lhs, ExprNodes.NameNode)
and Utils.long_literal(rhs.value)):
entry = lhs.entry or self.env.lookup(lhs.name)
if entry:
entry.might_overflow = True
def visit_SingleAssignmentNode(self, node):
self.visit_assignment(node.lhs, node.rhs)
self.visitchildren(node)
return node
def visit_CascadedAssignmentNode(self, node):
for lhs in node.lhs_list:
self.visit_assignment(lhs, node.rhs)
self.visitchildren(node)
return node
class PyObjectTypeInferer(object):
"""
If it's not declared, it's a PyObject.
"""
def infer_types(self, scope):
"""
Given a dict of entries, map all unspecified types to a specified type.
"""
for name, entry in scope.entries.items():
if entry.type is unspecified_type:
entry.type = py_object_type
class SimpleAssignmentTypeInferer(object):
"""
Very basic type inference.
"""
# TODO: Implement a real type inference algorithm.
# (Something more powerful than just extending this one...)
def infer_types(self, scope):
enabled = not scope.is_closure_scope and scope.directives['infer_types']
verbose = scope.directives['infer_types.verbose']
if enabled == True:
spanning_type = aggressive_spanning_type
elif enabled is None: # safe mode
spanning_type = safe_spanning_type
else:
for entry in scope.entries.values():
if entry.type is unspecified_type:
entry.type = py_object_type
if scope.is_closure_scope:
fix_closure_entries(scope)
return
dependancies_by_entry = {} # entry -> dependancies
entries_by_dependancy = {} # dependancy -> entries
ready_to_infer = []
for name, entry in scope.entries.items():
if entry.type is unspecified_type:
all = set()
for expr in entry.assignments:
all.update(expr.type_dependencies(scope))
if all:
dependancies_by_entry[entry] = all
for dep in all:
if dep not in entries_by_dependancy:
entries_by_dependancy[dep] = set([entry])
else:
entries_by_dependancy[dep].add(entry)
else:
ready_to_infer.append(entry)
def resolve_dependancy(dep):
if dep in entries_by_dependancy:
for entry in entries_by_dependancy[dep]:
entry_deps = dependancies_by_entry[entry]
entry_deps.remove(dep)
if not entry_deps and entry != dep:
del dependancies_by_entry[entry]
ready_to_infer.append(entry)
# Try to infer things in order...
while True:
while ready_to_infer:
entry = ready_to_infer.pop()
types = [expr.infer_type(scope) for expr in entry.assignments]
if types:
entry.type = spanning_type(types, entry.might_overflow)
else:
# FIXME: raise a warning?
# print "No assignments", entry.pos, entry
entry.type = py_object_type
if verbose:
message(entry.pos, "inferred '%s' to be of type '%s'" % (entry.name, entry.type))
resolve_dependancy(entry)
# Deal with simple circular dependancies...
for entry, deps in dependancies_by_entry.items():
if len(deps) == 1 and deps == set([entry]):
types = [expr.infer_type(scope) for expr in entry.assignments if expr.type_dependencies(scope) == ()]
if types:
entry.type = spanning_type(types, entry.might_overflow)
types = [expr.infer_type(scope) for expr in entry.assignments]
entry.type = spanning_type(types, entry.might_overflow) # might be wider...
resolve_dependancy(entry)
del dependancies_by_entry[entry]
if ready_to_infer:
break
if not ready_to_infer:
break
# We can't figure out the rest with this algorithm, let them be objects.
for entry in dependancies_by_entry:
entry.type = py_object_type
if verbose:
message(entry.pos, "inferred '%s' to be of type '%s' (default)" % (entry.name, entry.type))
#if scope.is_closure_scope:
# fix_closure_entries(scope)
def fix_closure_entries(scope):
"""Temporary work-around to fix field types in the closure class
that were unknown at the time of creation and only determined
during type inference.
"""
closure_entries = scope.scope_class.type.scope.entries
for name, entry in scope.entries.iteritems():
if name in closure_entries:
closure_entry = closure_entries[name]
closure_entry.type = entry.type
def find_spanning_type(type1, type2):
if type1 is type2:
result_type = type1
elif type1 is PyrexTypes.c_bint_type or type2 is PyrexTypes.c_bint_type:
# type inference can break the coercion back to a Python bool
# if it returns an arbitrary int type here
return py_object_type
else:
result_type = PyrexTypes.spanning_type(type1, type2)
if result_type in (PyrexTypes.c_double_type, PyrexTypes.c_float_type,
Builtin.float_type):
# Python's float type is just a C double, so it's safe to
# use the C type instead
return PyrexTypes.c_double_type
return result_type
def aggressive_spanning_type(types, might_overflow):
result_type = reduce(find_spanning_type, types)
if result_type.is_reference:
result_type = result_type.ref_base_type
return result_type
def safe_spanning_type(types, might_overflow):
result_type = reduce(find_spanning_type, types)
if result_type.is_reference:
result_type = result_type.ref_base_type
if result_type.is_pyobject:
# In theory, any specific Python type is always safe to
# infer. However, inferring str can cause some existing code
# to break, since we are also now much more strict about
# coercion from str to char *. See trac #553.
if result_type.name == 'str':
return py_object_type
else:
return result_type
elif result_type is PyrexTypes.c_double_type:
# Python's float type is just a C double, so it's safe to use
# the C type instead
return result_type
elif result_type is PyrexTypes.c_bint_type:
# find_spanning_type() only returns 'bint' for clean boolean
# operations without other int types, so this is safe, too
return result_type
elif result_type.is_ptr and not (result_type.is_int and result_type.rank == 0):
# Any pointer except (signed|unsigned|) char* can't implicitly
# become a PyObject.
return result_type
elif result_type.is_cpp_class:
# These can't implicitly become Python objects either.
return result_type
elif result_type.is_struct:
# Though we have struct -> object for some structs, this is uncommonly
# used, won't arise in pure Python, and there shouldn't be side
# effects, so I'm declaring this safe.
return result_type
# TODO: double complex should be OK as well, but we need
# to make sure everything is supported.
elif result_type.is_int and not might_overflow:
return result_type
return py_object_type
def get_type_inferer():
return SimpleAssignmentTypeInferer()
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/TypeSlots.py 0000664 0000000 0000000 00000072202 11446142532 0025305 0 ustar 00root root 0000000 0000000 #
# Pyrex - Tables describing slots in the type object
# and associated know-how.
#
import Naming
import PyrexTypes
import StringEncoding
import sys
invisible = ['__cinit__', '__dealloc__', '__richcmp__',
'__nonzero__', '__bool__']
class Signature(object):
# Method slot signature descriptor.
#
# has_dummy_arg boolean
# has_generic_args boolean
# fixed_arg_format string
# ret_format string
# error_value string
#
# The formats are strings made up of the following
# characters:
#
# 'O' Python object
# 'T' Python object of the type of 'self'
# 'v' void
# 'p' void *
# 'P' void **
# 'i' int
# 'b' bint
# 'I' int *
# 'l' long
# 'z' Py_ssize_t
# 'Z' Py_ssize_t *
# 's' char *
# 'S' char **
# 'r' int used only to signal exception
# 'B' Py_buffer *
# '-' dummy 'self' argument (not used)
# '*' rest of args passed as generic Python
# arg tuple and kw dict (must be last
# char in format string)
format_map = {
'O': PyrexTypes.py_object_type,
'v': PyrexTypes.c_void_type,
'p': PyrexTypes.c_void_ptr_type,
'P': PyrexTypes.c_void_ptr_ptr_type,
'i': PyrexTypes.c_int_type,
'b': PyrexTypes.c_bint_type,
'I': PyrexTypes.c_int_ptr_type,
'l': PyrexTypes.c_long_type,
'z': PyrexTypes.c_py_ssize_t_type,
'Z': PyrexTypes.c_py_ssize_t_ptr_type,
's': PyrexTypes.c_char_ptr_type,
'S': PyrexTypes.c_char_ptr_ptr_type,
'r': PyrexTypes.c_returncode_type,
'B': PyrexTypes.c_py_buffer_ptr_type,
# 'T', '-' and '*' are handled otherwise
# and are not looked up in here
}
error_value_map = {
'O': "NULL",
'i': "-1",
'b': "-1",
'l': "-1",
'r': "-1",
'z': "-1",
}
def __init__(self, arg_format, ret_format):
self.has_dummy_arg = 0
self.has_generic_args = 0
if arg_format[:1] == '-':
self.has_dummy_arg = 1
arg_format = arg_format[1:]
if arg_format[-1:] == '*':
self.has_generic_args = 1
arg_format = arg_format[:-1]
self.fixed_arg_format = arg_format
self.ret_format = ret_format
self.error_value = self.error_value_map.get(ret_format, None)
def num_fixed_args(self):
return len(self.fixed_arg_format)
def is_self_arg(self, i):
# argument is 'self' for methods or 'class' for classmethods
return self.fixed_arg_format[i] == 'T'
def fixed_arg_type(self, i):
return self.format_map[self.fixed_arg_format[i]]
def return_type(self):
return self.format_map[self.ret_format]
def exception_value(self):
return self.error_value_map.get(self.ret_format)
def function_type(self):
# Construct a C function type descriptor for this signature
args = []
for i in xrange(self.num_fixed_args()):
arg_type = self.fixed_arg_type(i)
args.append(PyrexTypes.CFuncTypeArg("", arg_type, None))
ret_type = self.return_type()
exc_value = self.exception_value()
return PyrexTypes.CFuncType(ret_type, args, exception_value = exc_value)
def method_flags(self):
if self.ret_format == "O":
full_args = self.fixed_arg_format
if self.has_dummy_arg:
full_args = "O" + full_args
if full_args in ["O", "T"]:
if self.has_generic_args:
return [method_varargs, method_keywords]
else:
return [method_noargs]
elif full_args in ["OO", "TO"] and not self.has_generic_args:
return [method_onearg]
return None
class SlotDescriptor(object):
# Abstract base class for type slot descriptors.
#
# slot_name string Member name of the slot in the type object
# is_initialised_dynamically Is initialised by code in the module init function
# py3 Indicates presence of slot in Python 3
# py2 Indicates presence of slot in Python 2
# ifdef Full #ifdef string that slot is wrapped in. Using this causes py3, py2 and flags to be ignored.)
def __init__(self, slot_name, dynamic=0,
py3=True, py2=True, ifdef=None):
self.slot_name = slot_name
self.is_initialised_dynamically = dynamic
self.ifdef = ifdef
self.py3 = py3
self.py2 = py2
def preprocessor_guard_code(self):
ifdef = self.ifdef
py2 = self.py2
py3 = self.py3
guard = None
if ifdef:
guard = ("#if %s" % ifdef)
elif not py3 or py3 == '':
guard = ("#if PY_MAJOR_VERSION < 3")
elif not py2:
guard = ("#if PY_MAJOR_VERSION >= 3")
return guard
def generate(self, scope, code):
if self.is_initialised_dynamically:
value = 0
else:
value = self.slot_code(scope)
preprocessor_guard = self.preprocessor_guard_code()
if preprocessor_guard:
code.putln(preprocessor_guard)
code.putln("%s, /*%s*/" % (value, self.slot_name))
if self.py3 == '':
code.putln("#else")
code.putln("0, /*reserved*/")
if preprocessor_guard:
code.putln("#endif")
# Some C implementations have trouble statically
# initialising a global with a pointer to an extern
# function, so we initialise some of the type slots
# in the module init function instead.
def generate_dynamic_init_code(self, scope, code):
if self.is_initialised_dynamically:
value = self.slot_code(scope)
if value != "0":
code.putln("%s.%s = %s;" % (
scope.parent_type.typeobj_cname,
self.slot_name,
value
)
)
class FixedSlot(SlotDescriptor):
# Descriptor for a type slot with a fixed value.
#
# value string
def __init__(self, slot_name, value, py3=True, py2=True, ifdef=None):
SlotDescriptor.__init__(self, slot_name, py3=py3, py2=py2, ifdef=ifdef)
self.value = value
def slot_code(self, scope):
return self.value
class EmptySlot(FixedSlot):
# Descriptor for a type slot whose value is always 0.
def __init__(self, slot_name, py3=True, py2=True, ifdef=None):
FixedSlot.__init__(self, slot_name, "0", py3=py3, py2=py2, ifdef=ifdef)
class MethodSlot(SlotDescriptor):
# Type slot descriptor for a user-definable method.
#
# signature Signature
# method_name string The __xxx__ name of the method
# alternatives [string] Alternative list of __xxx__ names for the method
def __init__(self, signature, slot_name, method_name, fallback=None,
py3=True, py2=True, ifdef=None):
SlotDescriptor.__init__(self, slot_name, py3=py3, py2=py2, ifdef=ifdef)
self.signature = signature
self.slot_name = slot_name
self.method_name = method_name
self.alternatives = []
method_name_to_slot[method_name] = self
#
if fallback:
self.alternatives.append(fallback)
for alt in (self.py2, self.py3):
if isinstance(alt, (tuple, list)):
slot_name, method_name = alt
self.alternatives.append(method_name)
method_name_to_slot[method_name] = self
def slot_code(self, scope):
entry = scope.lookup_here(self.method_name)
if entry and entry.func_cname:
return entry.func_cname
for method_name in self.alternatives:
entry = scope.lookup_here(method_name)
if entry and entry.func_cname:
return entry.func_cname
return "0"
class InternalMethodSlot(SlotDescriptor):
# Type slot descriptor for a method which is always
# synthesized by Cython.
#
# slot_name string Member name of the slot in the type object
def __init__(self, slot_name, **kargs):
SlotDescriptor.__init__(self, slot_name, **kargs)
def slot_code(self, scope):
return scope.mangle_internal(self.slot_name)
class GCDependentSlot(InternalMethodSlot):
# Descriptor for a slot whose value depends on whether
# the type participates in GC.
def __init__(self, slot_name, **kargs):
InternalMethodSlot.__init__(self, slot_name, **kargs)
def slot_code(self, scope):
if not scope.needs_gc():
return "0"
if not scope.has_pyobject_attrs:
# if the type does not have object attributes, it can
# delegate GC methods to its parent - iff the parent
# functions are defined in the same module
parent_type_scope = scope.parent_type.base_type.scope
if scope.parent_scope is parent_type_scope.parent_scope:
entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name)
if entry.visibility != 'extern':
return self.slot_code(parent_type_scope)
return InternalMethodSlot.slot_code(self, scope)
class ConstructorSlot(InternalMethodSlot):
# Descriptor for tp_new and tp_dealloc.
def __init__(self, slot_name, method, **kargs):
InternalMethodSlot.__init__(self, slot_name, **kargs)
self.method = method
def slot_code(self, scope):
if scope.parent_type.base_type \
and not scope.has_pyobject_attrs \
and not scope.lookup_here(self.method):
# if the type does not have object attributes, it can
# delegate GC methods to its parent - iff the parent
# functions are defined in the same module
parent_type_scope = scope.parent_type.base_type.scope
if scope.parent_scope is parent_type_scope.parent_scope:
entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name)
if entry.visibility != 'extern':
return self.slot_code(parent_type_scope)
return InternalMethodSlot.slot_code(self, scope)
class SyntheticSlot(InternalMethodSlot):
# Type slot descriptor for a synthesized method which
# dispatches to one or more user-defined methods depending
# on its arguments. If none of the relevant methods are
# defined, the method will not be synthesized and an
# alternative default value will be placed in the type
# slot.
def __init__(self, slot_name, user_methods, default_value, **kargs):
InternalMethodSlot.__init__(self, slot_name, **kargs)
self.user_methods = user_methods
self.default_value = default_value
def slot_code(self, scope):
if scope.defines_any(self.user_methods):
return InternalMethodSlot.slot_code(self, scope)
else:
return self.default_value
class TypeFlagsSlot(SlotDescriptor):
# Descriptor for the type flags slot.
def slot_code(self, scope):
value = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_NEWBUFFER"
if scope.needs_gc():
value += "|Py_TPFLAGS_HAVE_GC"
return value
class DocStringSlot(SlotDescriptor):
# Descriptor for the docstring slot.
def slot_code(self, scope):
if scope.doc is not None:
if scope.doc.is_unicode:
doc = scope.doc.utf8encode()
else:
doc = scope.doc.byteencode()
return '__Pyx_DOCSTR("%s")' % StringEncoding.escape_byte_string(doc)
else:
return "0"
class SuiteSlot(SlotDescriptor):
# Descriptor for a substructure of the type object.
#
# sub_slots [SlotDescriptor]
def __init__(self, sub_slots, slot_type, slot_name):
SlotDescriptor.__init__(self, slot_name)
self.sub_slots = sub_slots
self.slot_type = slot_type
substructures.append(self)
def substructure_cname(self, scope):
return "%s%s_%s" % (Naming.pyrex_prefix, self.slot_name, scope.class_name)
def slot_code(self, scope):
return "&%s" % self.substructure_cname(scope)
def generate_substructure(self, scope, code):
code.putln("")
code.putln(
"static %s %s = {" % (
self.slot_type,
self.substructure_cname(scope)))
for slot in self.sub_slots:
slot.generate(scope, code)
code.putln("};")
substructures = [] # List of all SuiteSlot instances
class MethodTableSlot(SlotDescriptor):
# Slot descriptor for the method table.
def slot_code(self, scope):
return scope.method_table_cname
class MemberTableSlot(SlotDescriptor):
# Slot descriptor for the table of Python-accessible attributes.
def slot_code(self, scope):
return "0"
class GetSetSlot(SlotDescriptor):
# Slot descriptor for the table of attribute get & set methods.
def slot_code(self, scope):
if scope.property_entries:
return scope.getset_table_cname
else:
return "0"
class BaseClassSlot(SlotDescriptor):
# Slot descriptor for the base class slot.
def __init__(self, name):
SlotDescriptor.__init__(self, name, dynamic = 1)
def generate_dynamic_init_code(self, scope, code):
base_type = scope.parent_type.base_type
if base_type:
code.putln("%s.%s = %s;" % (
scope.parent_type.typeobj_cname,
self.slot_name,
base_type.typeptr_cname))
# The following dictionary maps __xxx__ method names to slot descriptors.
method_name_to_slot = {}
## The following slots are (or could be) initialised with an
## extern function pointer.
#
#slots_initialised_from_extern = (
# "tp_free",
#)
#------------------------------------------------------------------------------------------
#
# Utility functions for accessing slot table data structures
#
#------------------------------------------------------------------------------------------
def get_special_method_signature(name):
# Given a method name, if it is a special method,
# return its signature, else return None.
slot = method_name_to_slot.get(name)
if slot:
return slot.signature
else:
return None
def get_property_accessor_signature(name):
# Return signature of accessor for an extension type
# property, else None.
return property_accessor_signatures.get(name)
def get_base_slot_function(scope, slot):
# Returns the function implementing this slot in the baseclass.
# This is useful for enabling the compiler to optimize calls
# that recursively climb the class hierarchy.
base_type = scope.parent_type.base_type
if scope.parent_scope is base_type.scope.parent_scope:
parent_slot = slot.slot_code(base_type.scope)
if parent_slot != '0':
entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name)
if entry.visibility != 'extern':
return parent_slot
return None
#------------------------------------------------------------------------------------------
#
# Signatures for generic Python functions and methods.
#
#------------------------------------------------------------------------------------------
pyfunction_signature = Signature("-*", "O")
pymethod_signature = Signature("T*", "O")
#------------------------------------------------------------------------------------------
#
# Signatures for simple Python functions.
#
#------------------------------------------------------------------------------------------
pyfunction_noargs = Signature("-", "O")
pyfunction_onearg = Signature("-O", "O")
#------------------------------------------------------------------------------------------
#
# Signatures for the various kinds of function that
# can appear in the type object and its substructures.
#
#------------------------------------------------------------------------------------------
unaryfunc = Signature("T", "O") # typedef PyObject * (*unaryfunc)(PyObject *);
binaryfunc = Signature("OO", "O") # typedef PyObject * (*binaryfunc)(PyObject *, PyObject *);
ibinaryfunc = Signature("TO", "O") # typedef PyObject * (*binaryfunc)(PyObject *, PyObject *);
ternaryfunc = Signature("OOO", "O") # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *);
iternaryfunc = Signature("TOO", "O") # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *);
callfunc = Signature("T*", "O") # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *);
inquiry = Signature("T", "i") # typedef int (*inquiry)(PyObject *);
lenfunc = Signature("T", "z") # typedef Py_ssize_t (*lenfunc)(PyObject *);
# typedef int (*coercion)(PyObject **, PyObject **);
intargfunc = Signature("Ti", "O") # typedef PyObject *(*intargfunc)(PyObject *, int);
ssizeargfunc = Signature("Tz", "O") # typedef PyObject *(*ssizeargfunc)(PyObject *, Py_ssize_t);
intintargfunc = Signature("Tii", "O") # typedef PyObject *(*intintargfunc)(PyObject *, int, int);
ssizessizeargfunc = Signature("Tzz", "O") # typedef PyObject *(*ssizessizeargfunc)(PyObject *, Py_ssize_t, Py_ssize_t);
intobjargproc = Signature("TiO", 'r') # typedef int(*intobjargproc)(PyObject *, int, PyObject *);
ssizeobjargproc = Signature("TzO", 'r') # typedef int(*ssizeobjargproc)(PyObject *, Py_ssize_t, PyObject *);
intintobjargproc = Signature("TiiO", 'r') # typedef int(*intintobjargproc)(PyObject *, int, int, PyObject *);
ssizessizeobjargproc = Signature("TzzO", 'r') # typedef int(*ssizessizeobjargproc)(PyObject *, Py_ssize_t, Py_ssize_t, PyObject *);
intintargproc = Signature("Tii", 'r')
ssizessizeargproc = Signature("Tzz", 'r')
objargfunc = Signature("TO", "O")
objobjargproc = Signature("TOO", 'r') # typedef int (*objobjargproc)(PyObject *, PyObject *, PyObject *);
readbufferproc = Signature("TzP", "z") # typedef Py_ssize_t (*readbufferproc)(PyObject *, Py_ssize_t, void **);
writebufferproc = Signature("TzP", "z") # typedef Py_ssize_t (*writebufferproc)(PyObject *, Py_ssize_t, void **);
segcountproc = Signature("TZ", "z") # typedef Py_ssize_t (*segcountproc)(PyObject *, Py_ssize_t *);
charbufferproc = Signature("TzS", "z") # typedef Py_ssize_t (*charbufferproc)(PyObject *, Py_ssize_t, char **);
objargproc = Signature("TO", 'r') # typedef int (*objobjproc)(PyObject *, PyObject *);
# typedef int (*visitproc)(PyObject *, void *);
# typedef int (*traverseproc)(PyObject *, visitproc, void *);
destructor = Signature("T", "v") # typedef void (*destructor)(PyObject *);
# printfunc = Signature("TFi", 'r') # typedef int (*printfunc)(PyObject *, FILE *, int);
# typedef PyObject *(*getattrfunc)(PyObject *, char *);
getattrofunc = Signature("TO", "O") # typedef PyObject *(*getattrofunc)(PyObject *, PyObject *);
# typedef int (*setattrfunc)(PyObject *, char *, PyObject *);
setattrofunc = Signature("TOO", 'r') # typedef int (*setattrofunc)(PyObject *, PyObject *, PyObject *);
delattrofunc = Signature("TO", 'r')
cmpfunc = Signature("TO", "i") # typedef int (*cmpfunc)(PyObject *, PyObject *);
reprfunc = Signature("T", "O") # typedef PyObject *(*reprfunc)(PyObject *);
hashfunc = Signature("T", "l") # typedef long (*hashfunc)(PyObject *);
# typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int);
richcmpfunc = Signature("OOi", "O") # typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int);
getiterfunc = Signature("T", "O") # typedef PyObject *(*getiterfunc) (PyObject *);
iternextfunc = Signature("T", "O") # typedef PyObject *(*iternextfunc) (PyObject *);
descrgetfunc = Signature("TOO", "O") # typedef PyObject *(*descrgetfunc) (PyObject *, PyObject *, PyObject *);
descrsetfunc = Signature("TOO", 'r') # typedef int (*descrsetfunc) (PyObject *, PyObject *, PyObject *);
descrdelfunc = Signature("TO", 'r')
initproc = Signature("T*", 'r') # typedef int (*initproc)(PyObject *, PyObject *, PyObject *);
# typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *);
# typedef PyObject *(*allocfunc)(struct _typeobject *, int);
getbufferproc = Signature("TBi", "r") # typedef int (*getbufferproc)(PyObject *, Py_buffer *, int);
releasebufferproc = Signature("TB", "v") # typedef void (*releasebufferproc)(PyObject *, Py_buffer *);
#------------------------------------------------------------------------------------------
#
# Signatures for accessor methods of properties.
#
#------------------------------------------------------------------------------------------
property_accessor_signatures = {
'__get__': Signature("T", "O"),
'__set__': Signature("TO", 'r'),
'__del__': Signature("T", 'r')
}
#------------------------------------------------------------------------------------------
#
# Descriptor tables for the slots of the various type object
# substructures, in the order they appear in the structure.
#
#------------------------------------------------------------------------------------------
PyNumberMethods = (
MethodSlot(binaryfunc, "nb_add", "__add__"),
MethodSlot(binaryfunc, "nb_subtract", "__sub__"),
MethodSlot(binaryfunc, "nb_multiply", "__mul__"),
MethodSlot(binaryfunc, "nb_divide", "__div__", py3 = False),
MethodSlot(binaryfunc, "nb_remainder", "__mod__"),
MethodSlot(binaryfunc, "nb_divmod", "__divmod__"),
MethodSlot(ternaryfunc, "nb_power", "__pow__"),
MethodSlot(unaryfunc, "nb_negative", "__neg__"),
MethodSlot(unaryfunc, "nb_positive", "__pos__"),
MethodSlot(unaryfunc, "nb_absolute", "__abs__"),
MethodSlot(inquiry, "nb_nonzero", "__nonzero__", py3 = ("nb_bool", "__bool__")),
MethodSlot(unaryfunc, "nb_invert", "__invert__"),
MethodSlot(binaryfunc, "nb_lshift", "__lshift__"),
MethodSlot(binaryfunc, "nb_rshift", "__rshift__"),
MethodSlot(binaryfunc, "nb_and", "__and__"),
MethodSlot(binaryfunc, "nb_xor", "__xor__"),
MethodSlot(binaryfunc, "nb_or", "__or__"),
EmptySlot("nb_coerce", py3 = False),
MethodSlot(unaryfunc, "nb_int", "__int__", fallback="__long__"),
MethodSlot(unaryfunc, "nb_long", "__long__", fallback="__int__", py3 = ""),
MethodSlot(unaryfunc, "nb_float", "__float__"),
MethodSlot(unaryfunc, "nb_oct", "__oct__", py3 = False),
MethodSlot(unaryfunc, "nb_hex", "__hex__", py3 = False),
# 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__", py3 = False),
MethodSlot(ibinaryfunc, "nb_inplace_remainder", "__imod__"),
MethodSlot(ternaryfunc, "nb_inplace_power", "__ipow__"), # NOT iternaryfunc!!!
MethodSlot(ibinaryfunc, "nb_inplace_lshift", "__ilshift__"),
MethodSlot(ibinaryfunc, "nb_inplace_rshift", "__irshift__"),
MethodSlot(ibinaryfunc, "nb_inplace_and", "__iand__"),
MethodSlot(ibinaryfunc, "nb_inplace_xor", "__ixor__"),
MethodSlot(ibinaryfunc, "nb_inplace_or", "__ior__"),
# Added in release 2.2
# The following require the Py_TPFLAGS_HAVE_CLASS flag
MethodSlot(binaryfunc, "nb_floor_divide", "__floordiv__"),
MethodSlot(binaryfunc, "nb_true_divide", "__truediv__"),
MethodSlot(ibinaryfunc, "nb_inplace_floor_divide", "__ifloordiv__"),
MethodSlot(ibinaryfunc, "nb_inplace_true_divide", "__itruediv__"),
# Added in release 2.5
MethodSlot(unaryfunc, "nb_index", "__index__", ifdef = "PY_VERSION_HEX >= 0x02050000")
)
PySequenceMethods = (
MethodSlot(lenfunc, "sq_length", "__len__"),
EmptySlot("sq_concat"), # nb_add used instead
EmptySlot("sq_repeat"), # nb_multiply used instead
SyntheticSlot("sq_item", ["__getitem__"], "0"), #EmptySlot("sq_item"), # mp_subscript used instead
MethodSlot(ssizessizeargfunc, "sq_slice", "__getslice__"),
EmptySlot("sq_ass_item"), # mp_ass_subscript used instead
SyntheticSlot("sq_ass_slice", ["__setslice__", "__delslice__"], "0"),
MethodSlot(cmpfunc, "sq_contains", "__contains__"),
EmptySlot("sq_inplace_concat"), # nb_inplace_add used instead
EmptySlot("sq_inplace_repeat"), # nb_inplace_multiply used instead
)
PyMappingMethods = (
MethodSlot(lenfunc, "mp_length", "__len__"),
MethodSlot(objargfunc, "mp_subscript", "__getitem__"),
SyntheticSlot("mp_ass_subscript", ["__setitem__", "__delitem__"], "0"),
)
PyBufferProcs = (
MethodSlot(readbufferproc, "bf_getreadbuffer", "__getreadbuffer__", py3 = False),
MethodSlot(writebufferproc, "bf_getwritebuffer", "__getwritebuffer__", py3 = False),
MethodSlot(segcountproc, "bf_getsegcount", "__getsegcount__", py3 = False),
MethodSlot(charbufferproc, "bf_getcharbuffer", "__getcharbuffer__", py3 = False),
MethodSlot(getbufferproc, "bf_getbuffer", "__getbuffer__", ifdef = "PY_VERSION_HEX >= 0x02060000"),
MethodSlot(releasebufferproc, "bf_releasebuffer", "__releasebuffer__", ifdef = "PY_VERSION_HEX >= 0x02060000")
)
#------------------------------------------------------------------------------------------
#
# The main slot table. This table contains descriptors for all the
# top-level type slots, beginning with tp_dealloc, in the order they
# appear in the type object.
#
#------------------------------------------------------------------------------------------
slot_table = (
ConstructorSlot("tp_dealloc", '__dealloc__'),
EmptySlot("tp_print"), #MethodSlot(printfunc, "tp_print", "__print__"),
EmptySlot("tp_getattr"),
EmptySlot("tp_setattr"),
MethodSlot(cmpfunc, "tp_compare", "__cmp__", py3 = ''),
MethodSlot(reprfunc, "tp_repr", "__repr__"),
SuiteSlot(PyNumberMethods, "PyNumberMethods", "tp_as_number"),
SuiteSlot(PySequenceMethods, "PySequenceMethods", "tp_as_sequence"),
SuiteSlot(PyMappingMethods, "PyMappingMethods", "tp_as_mapping"),
MethodSlot(hashfunc, "tp_hash", "__hash__"),
MethodSlot(callfunc, "tp_call", "__call__"),
MethodSlot(reprfunc, "tp_str", "__str__"),
SyntheticSlot("tp_getattro", ["__getattr__","__getattribute__"], "0"), #"PyObject_GenericGetAttr"),
SyntheticSlot("tp_setattro", ["__setattr__", "__delattr__"], "0"), #"PyObject_GenericSetAttr"),
SuiteSlot(PyBufferProcs, "PyBufferProcs", "tp_as_buffer"),
TypeFlagsSlot("tp_flags"),
DocStringSlot("tp_doc"),
GCDependentSlot("tp_traverse"),
GCDependentSlot("tp_clear"),
# Later -- synthesize a method to split into separate ops?
MethodSlot(richcmpfunc, "tp_richcompare", "__richcmp__"),
EmptySlot("tp_weaklistoffset"),
MethodSlot(getiterfunc, "tp_iter", "__iter__"),
MethodSlot(iternextfunc, "tp_iternext", "__next__"),
MethodTableSlot("tp_methods"),
MemberTableSlot("tp_members"),
GetSetSlot("tp_getset"),
BaseClassSlot("tp_base"), #EmptySlot("tp_base"),
EmptySlot("tp_dict"),
SyntheticSlot("tp_descr_get", ["__get__"], "0"),
SyntheticSlot("tp_descr_set", ["__set__", "__delete__"], "0"),
EmptySlot("tp_dictoffset"),
MethodSlot(initproc, "tp_init", "__init__"),
EmptySlot("tp_alloc"), #FixedSlot("tp_alloc", "PyType_GenericAlloc"),
InternalMethodSlot("tp_new"),
EmptySlot("tp_free"),
EmptySlot("tp_is_gc"),
EmptySlot("tp_bases"),
EmptySlot("tp_mro"),
EmptySlot("tp_cache"),
EmptySlot("tp_subclasses"),
EmptySlot("tp_weaklist"),
EmptySlot("tp_del"),
EmptySlot("tp_version_tag", ifdef="PY_VERSION_HEX >= 0x02060000"),
)
#------------------------------------------------------------------------------------------
#
# Descriptors for special methods which don't appear directly
# in the type object or its substructures. These methods are
# called from slot functions synthesized by Cython.
#
#------------------------------------------------------------------------------------------
MethodSlot(initproc, "", "__cinit__")
MethodSlot(destructor, "", "__dealloc__")
MethodSlot(objobjargproc, "", "__setitem__")
MethodSlot(objargproc, "", "__delitem__")
MethodSlot(ssizessizeobjargproc, "", "__setslice__")
MethodSlot(ssizessizeargproc, "", "__delslice__")
MethodSlot(getattrofunc, "", "__getattr__")
MethodSlot(setattrofunc, "", "__setattr__")
MethodSlot(delattrofunc, "", "__delattr__")
MethodSlot(descrgetfunc, "", "__get__")
MethodSlot(descrsetfunc, "", "__set__")
MethodSlot(descrdelfunc, "", "__delete__")
# Method flags for python-exposed methods.
method_noargs = "METH_NOARGS"
method_onearg = "METH_O"
method_varargs = "METH_VARARGS"
method_keywords = "METH_KEYWORDS"
method_coexist = "METH_COEXIST"
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/UtilNodes.py 0000664 0000000 0000000 00000024001 11446142532 0025237 0 ustar 00root root 0000000 0000000 #
# Nodes used as utilities and support for transforms etc.
# These often make up sets including both Nodes and ExprNodes
# so it is convenient to have them in a seperate module.
#
import Nodes
import ExprNodes
from Nodes import Node
from ExprNodes import AtomicExprNode
class TempHandle(object):
# THIS IS DEPRECATED, USE LetRefNode instead
temp = None
needs_xdecref = False
def __init__(self, type):
self.type = type
self.needs_cleanup = type.is_pyobject
def ref(self, pos):
return TempRefNode(pos, handle=self, type=self.type)
def cleanup_ref(self, pos):
return CleanupTempRefNode(pos, handle=self, type=self.type)
class TempRefNode(AtomicExprNode):
# THIS IS DEPRECATED, USE LetRefNode instead
# handle TempHandle
def analyse_types(self, env):
assert self.type == self.handle.type
def analyse_target_types(self, env):
assert self.type == self.handle.type
def analyse_target_declaration(self, env):
pass
def calculate_result_code(self):
result = self.handle.temp
if result is None: result = "" # might be called and overwritten
return result
def generate_result_code(self, code):
pass
def generate_assignment_code(self, rhs, code):
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_as(self.ctype())))
rhs.generate_post_assignment_code(code)
rhs.free_temps(code)
class CleanupTempRefNode(TempRefNode):
# THIS IS DEPRECATED, USE LetRefNode instead
# handle TempHandle
def generate_assignment_code(self, rhs, code):
pass
def generate_execution_code(self, code):
if self.type.is_pyobject:
code.put_decref_clear(self.result(), self.type)
self.handle.needs_cleanup = False
class TempsBlockNode(Node):
# THIS IS DEPRECATED, USE LetNode instead
"""
Creates a block which allocates temporary variables.
This is used by transforms to output constructs that need
to make use of a temporary variable. Simply pass the types
of the needed temporaries to the constructor.
The variables can be referred to using a TempRefNode
(which can be constructed by calling get_ref_node).
"""
# temps [TempHandle]
# body StatNode
child_attrs = ["body"]
def generate_execution_code(self, code):
for handle in self.temps:
handle.temp = code.funcstate.allocate_temp(
handle.type, manage_ref=handle.needs_cleanup)
self.body.generate_execution_code(code)
for handle in self.temps:
if handle.needs_cleanup:
if handle.needs_xdecref:
code.put_xdecref_clear(handle.temp, handle.type)
else:
code.put_decref_clear(handle.temp, handle.type)
code.funcstate.release_temp(handle.temp)
def analyse_control_flow(self, env):
self.body.analyse_control_flow(env)
def analyse_declarations(self, env):
self.body.analyse_declarations(env)
def analyse_expressions(self, env):
self.body.analyse_expressions(env)
def generate_function_definitions(self, env, code):
self.body.generate_function_definitions(env, code)
def annotate(self, code):
self.body.annotate(code)
class ResultRefNode(AtomicExprNode):
# A reference to the result of an expression. The result_code
# must be set externally (usually a temp name).
subexprs = []
lhs_of_first_assignment = False
def __init__(self, expression=None, pos=None, type=None):
self.expression = expression
self.pos = None
if expression is not None:
self.pos = expression.pos
if hasattr(expression, "type"):
self.type = expression.type
if pos is not None:
self.pos = pos
if type is not None:
self.type = type
assert self.pos is not None
def analyse_types(self, env):
if self.expression is not None:
self.type = self.expression.type
def infer_type(self, env):
if self.expression is not None:
return self.expression.infer_type(env)
def _DISABLED_may_be_none(self):
# not sure if this is safe - the expression may not be the
# only value that gets assigned
if self.expression is not None:
return self.expression.may_be_none()
if self.type is not None:
return self.type.is_pyobject
return True # play safe
def is_simple(self):
return True
def result(self):
try:
return self.result_code
except AttributeError:
if self.expression is not None:
self.result_code = self.expression.result()
return self.result_code
def generate_evaluation_code(self, code):
pass
def generate_result_code(self, code):
pass
def generate_disposal_code(self, code):
pass
def generate_assignment_code(self, rhs, code):
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_as(self.ctype())))
rhs.generate_post_assignment_code(code)
rhs.free_temps(code)
def allocate_temps(self, env):
pass
def release_temp(self, env):
pass
def free_temps(self, code):
pass
class LetNodeMixin:
def set_temp_expr(self, lazy_temp):
self.lazy_temp = lazy_temp
self.temp_expression = lazy_temp.expression
def setup_temp_expr(self, code):
self.temp_expression.generate_evaluation_code(code)
self.temp_type = self.temp_expression.type
self._result_in_temp = self.temp_expression.result_in_temp()
if self._result_in_temp:
self.temp = self.temp_expression.result()
else:
self.temp_expression.make_owned_reference(code)
self.temp = code.funcstate.allocate_temp(
self.temp_type, manage_ref=True)
code.putln("%s = %s;" % (self.temp, self.temp_expression.result()))
self.temp_expression.generate_disposal_code(code)
self.temp_expression.free_temps(code)
self.lazy_temp.result_code = self.temp
def teardown_temp_expr(self, code):
if self._result_in_temp:
self.temp_expression.generate_disposal_code(code)
self.temp_expression.free_temps(code)
else:
if self.temp_type.is_pyobject:
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.
subexprs = ['temp_expression', 'subexpression']
def __init__(self, lazy_temp, subexpression):
self.set_temp_expr(lazy_temp)
self.pos = subexpression.pos
self.subexpression = subexpression
# if called after type analysis, we already know the type here
self.type = self.subexpression.type
def infer_type(self, env):
return self.subexpression.infer_type(env)
def result(self):
return self.subexpression.result()
def analyse_types(self, env):
self.temp_expression.analyse_types(env)
self.subexpression.analyse_types(env)
self.type = self.subexpression.type
def free_subexpr_temps(self, code):
self.subexpression.free_temps(code)
def generate_subexpr_disposal_code(self, code):
self.subexpression.generate_disposal_code(code)
def generate_evaluation_code(self, code):
self.setup_temp_expr(code)
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:
# let temp = VALUE:
# BLOCK (can modify temp)
# if temp is an object, decref
#
# Usually used after analysis phase, but forwards analysis methods
# to its children
child_attrs = ['temp_expression', 'body']
def __init__(self, lazy_temp, body):
self.set_temp_expr(lazy_temp)
self.pos = body.pos
self.body = body
def analyse_control_flow(self, env):
self.body.analyse_control_flow(env)
def analyse_declarations(self, env):
self.temp_expression.analyse_declarations(env)
self.body.analyse_declarations(env)
def analyse_expressions(self, env):
self.temp_expression.analyse_expressions(env)
self.body.analyse_expressions(env)
def generate_execution_code(self, code):
self.setup_temp_expr(code)
self.body.generate_execution_code(code)
self.teardown_temp_expr(code)
class TempResultFromStatNode(ExprNodes.ExprNode):
# An ExprNode wrapper around a StatNode that executes the StatNode
# body. Requires a ResultRefNode that it sets up to refer to its
# own temp result. The StatNode must assign a value to the result
# node, which then becomes the result of this node.
subexprs = []
child_attrs = ['body']
def __init__(self, result_ref, body):
self.result_ref = result_ref
self.pos = body.pos
self.body = body
self.type = result_ref.type
self.is_temp = 1
def analyse_declarations(self, env):
self.body.analyse_declarations(env)
def analyse_types(self, env):
self.body.analyse_expressions(env)
def generate_result_code(self, code):
self.result_ref.result_code = self.result()
self.body.generate_execution_code(code)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Version.py 0000664 0000000 0000000 00000000021 11446142532 0024752 0 ustar 00root root 0000000 0000000 version = '0.13'
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Visitor.pxd 0000664 0000000 0000000 00000001161 11446142532 0025135 0 ustar 00root root 0000000 0000000 cimport cython
cdef class BasicVisitor:
cdef dict dispatch_table
cpdef visit(self, obj)
cpdef find_handler(self, obj)
cdef class TreeVisitor(BasicVisitor):
cdef public list access_path
cpdef visitchild(self, child, parent, attrname, idx)
@cython.locals(idx=int)
cpdef dict _visitchildren(self, parent, attrs)
# cpdef visitchildren(self, parent, attrs=*)
cdef class VisitorTransform(TreeVisitor):
cpdef visitchildren(self, parent, attrs=*)
cpdef recurse_to_children(self, node)
cdef class CythonTransform(VisitorTransform):
cdef public context
cdef public current_directives
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/Visitor.py 0000664 0000000 0000000 00000036412 11446142532 0025001 0 ustar 00root root 0000000 0000000 # cython: infer_types=True
#
# Tree visitor and transform framework
#
import cython
import inspect
import Nodes
import ExprNodes
import Naming
import Errors
import DebugFlags
class BasicVisitor(object):
"""A generic visitor base class which can be used for visiting any kind of object."""
# Note: If needed, this can be replaced with a more efficient metaclass
# approach, resolving the jump table at module load time rather than per visitor
# instance.
def __init__(self):
self.dispatch_table = {}
def visit(self, obj):
try:
handler_method = self.dispatch_table[type(obj)]
except KeyError:
handler_method = self.find_handler(obj)
self.dispatch_table[type(obj)] = handler_method
return handler_method(obj)
def find_handler(self, obj):
cls = type(obj)
#print "Cache miss for class %s in visitor %s" % (
# cls.__name__, type(self).__name__)
# Must resolve, try entire hierarchy
pattern = "visit_%s"
mro = inspect.getmro(cls)
handler_method = None
for mro_cls in mro:
if hasattr(self, pattern % mro_cls.__name__):
handler_method = getattr(self, pattern % mro_cls.__name__)
break
if handler_method is None:
print type(self), cls
if hasattr(self, 'access_path') and self.access_path:
print self.access_path
if 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))
#print "Caching " + cls.__name__
return handler_method
class TreeVisitor(BasicVisitor):
"""
Base class for writing visitors for a Cython tree, contains utilities for
recursing such trees using visitors. Each node is
expected to have a child_attrs iterable containing the names of attributes
containing child nodes or lists of child nodes. Lists are not considered
part of the tree structure (i.e. contained nodes are considered direct
children of the parent node).
visit_children visits each of the children of a given node (see the visit_children
documentation). When recursing the tree using visit_children, an attribute
access_path is maintained which gives information about the current location
in the tree as a stack of tuples: (parent_node, attrname, index), representing
the node, attribute and optional list index that was taken in each step in the path to
the current node.
Example:
>>> class SampleNode(object):
... child_attrs = ["head", "body"]
... def __init__(self, value, head=None, body=None):
... self.value = value
... self.head = head
... self.body = body
... def __repr__(self): return "SampleNode(%s)" % self.value
...
>>> tree = SampleNode(0, SampleNode(1), [SampleNode(2), SampleNode(3)])
>>> class MyVisitor(TreeVisitor):
... def visit_SampleNode(self, node):
... print "in", node.value, self.access_path
... self.visitchildren(node)
... print "out", node.value
...
>>> MyVisitor().visit(tree)
in 0 []
in 1 [(SampleNode(0), 'head', None)]
out 1
in 2 [(SampleNode(0), 'body', 0)]
out 2
in 3 [(SampleNode(0), 'body', 1)]
out 3
out 0
"""
def __init__(self):
super(TreeVisitor, self).__init__()
self.access_path = []
def dump_node(self, node, indent=0):
ignored = list(node.child_attrs) + [u'child_attrs', u'pos',
u'gil_message', u'cpp_message',
u'subexprs']
values = []
pos = node.pos
if pos:
source = pos[0]
if source:
import os.path
source = os.path.basename(source.get_description())
values.append(u'%s:%s:%s' % (source, pos[1], pos[2]))
attribute_names = dir(node)
attribute_names.sort()
for attr in attribute_names:
if attr in ignored:
continue
if attr.startswith(u'_') or attr.endswith(u'_'):
continue
try:
value = getattr(node, attr)
except AttributeError:
continue
if value is None or value == 0:
continue
elif isinstance(value, list):
value = u'[...]/%d' % len(value)
elif not isinstance(value, (str, unicode, long, int, float)):
continue
else:
value = repr(value)
values.append(u'%s = %s' % (attr, value))
return u'%s(%s)' % (node.__class__.__name__,
u',\n '.join(values))
def _find_node_path(self, stacktrace):
import os.path
last_traceback = stacktrace
nodes = []
while hasattr(stacktrace, 'tb_frame'):
frame = stacktrace.tb_frame
node = frame.f_locals.get(u'self')
if isinstance(node, Nodes.Node):
code = frame.f_code
method_name = code.co_name
pos = (os.path.basename(code.co_filename),
code.co_firstlineno)
nodes.append((node, method_name, pos))
last_traceback = stacktrace
stacktrace = stacktrace.tb_next
return (last_traceback, nodes)
def _raise_compiler_error(self, child, e):
import sys
trace = ['']
for parent, attribute, index in self.access_path:
node = getattr(parent, attribute)
if index is None:
index = ''
else:
node = node[index]
index = u'[%d]' % index
trace.append(u'%s.%s%s = %s' % (
parent.__class__.__name__, attribute, index,
self.dump_node(node)))
stacktrace, called_nodes = self._find_node_path(sys.exc_info()[2])
last_node = child
for node, method_name, pos in called_nodes:
last_node = node
trace.append(u"File '%s', line %d, in %s: %s" % (
pos[0], pos[1], method_name, self.dump_node(node)))
raise Errors.CompilerCrash(
last_node.pos, self.__class__.__name__,
u'\n'.join(trace), e, stacktrace)
def visitchild(self, child, parent, attrname, idx):
self.access_path.append((parent, attrname, idx))
try:
result = self.visit(child)
except Errors.CompileError:
raise
except Exception, e:
if DebugFlags.debug_no_exception_intercept:
raise
self._raise_compiler_error(child, e)
self.access_path.pop()
return result
def visitchildren(self, parent, attrs=None):
return self._visitchildren(parent, attrs)
def _visitchildren(self, parent, attrs):
"""
Visits the children of the given parent. If parent is None, returns
immediately (returning None).
The return value is a dictionary giving the results for each
child (mapping the attribute name to either the return value
or a list of return values (in the case of multiple children
in an attribute)).
"""
if parent is None: return None
result = {}
for attr in parent.child_attrs:
if attrs is not None and attr not in attrs: continue
child = getattr(parent, attr)
if child is not None:
if type(child) is list:
childretval = [self.visitchild(x, parent, attr, idx) for idx, x in enumerate(child)]
else:
childretval = self.visitchild(child, parent, attr, None)
assert not isinstance(childretval, list), 'Cannot insert list here: %s in %r' % (attr, parent)
result[attr] = childretval
return result
class VisitorTransform(TreeVisitor):
"""
A tree transform is a base class for visitors that wants to do stream
processing of the structure (rather than attributes etc.) of a tree.
It implements __call__ to simply visit the argument node.
It requires the visitor methods to return the nodes which should take
the place of the visited node in the result tree (which can be the same
or one or more replacement). Specifically, if the return value from
a visitor method is:
- [] or None; the visited node will be removed (set to None if an attribute and
removed if in a list)
- A single node; the visited node will be replaced by the returned node.
- A list of nodes; the visited nodes will be replaced by all the nodes in the
list. This will only work if the node was already a member of a list; if it
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):
result = self._visitchildren(parent, attrs)
for attr, newnode in result.iteritems():
if not type(newnode) is list:
setattr(parent, attr, newnode)
else:
# Flatten the list one level and remove any None
newlist = []
for x in newnode:
if x is not None:
if type(x) is list:
newlist += x
else:
newlist.append(x)
setattr(parent, attr, newlist)
return result
def recurse_to_children(self, node):
self.visitchildren(node)
return node
def __call__(self, root):
return self.visit(root)
class CythonTransform(VisitorTransform):
"""
Certain common conventions and utilities for Cython transforms.
- Sets up the context of the pipeline in self.context
- Tracks directives in effect in self.current_directives
"""
def __init__(self, context):
super(CythonTransform, self).__init__()
self.context = context
def __call__(self, node):
import ModuleNode
if isinstance(node, ModuleNode.ModuleNode):
self.current_directives = node.directives
return super(CythonTransform, self).__call__(node)
def visit_CompilerDirectivesNode(self, node):
old = self.current_directives
self.current_directives = node.directives
self.visitchildren(node)
self.current_directives = old
return node
def visit_Node(self, node):
self.visitchildren(node)
return node
class ScopeTrackingTransform(CythonTransform):
# Keeps track of type of scopes
scope_type = None # can be either of 'module', 'function', 'cclass', 'pyclass'
scope_node = None
def visit_ModuleNode(self, node):
self.scope_type = 'module'
self.scope_node = node
self.visitchildren(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.visitchildren(node)
self.scope_type, self.scope_node = prev
return node
def visit_CClassDefNode(self, node):
return self.visit_scope(node, 'cclass')
def visit_PyClassDefNode(self, node):
return self.visit_scope(node, 'pyclass')
def visit_FuncDefNode(self, node):
return self.visit_scope(node, 'function')
def visit_CStructOrUnionDefNode(self, node):
return self.visit_scope(node, 'struct')
class EnvTransform(CythonTransform):
"""
This transformation keeps a stack of the environments.
"""
def __call__(self, root):
self.env_stack = [root.scope]
return super(EnvTransform, self).__call__(root)
def current_env(self):
return self.env_stack[-1]
def visit_FuncDefNode(self, node):
self.env_stack.append(node.local_scope)
self.visitchildren(node)
self.env_stack.pop()
return node
class RecursiveNodeReplacer(VisitorTransform):
"""
Recursively replace all occurrences of a node in a subtree by
another node.
"""
def __init__(self, orig_node, new_node):
super(RecursiveNodeReplacer, self).__init__()
self.orig_node, self.new_node = orig_node, new_node
def visit_Node(self, node):
self.visitchildren(node)
if node is self.orig_node:
return self.new_node
else:
return node
def recursively_replace_node(tree, old_node, new_node):
replace_in = RecursiveNodeReplacer(old_node, new_node)
replace_in(tree)
# Utils
def ensure_statlist(node):
if not isinstance(node, Nodes.StatListNode):
node = Nodes.StatListNode(pos=node.pos, stats=[node])
return node
def replace_node(ptr, value):
"""Replaces a node. ptr is of the form used on the access path stack
(parent, attrname, listidx|None)
"""
parent, attrname, listidx = ptr
if listidx is None:
setattr(parent, attrname, 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):
TreeVisitor.__init__(self)
self._indent = ""
def indent(self):
self._indent += " "
def unindent(self):
self._indent = self._indent[:-2]
def __call__(self, tree, phase=None):
print("Parse tree dump at phase '%s'" % phase)
self.visit(tree)
return tree
# Don't do anything about process_list, the defaults gives
# nice-looking name[idx] nodes which will visually appear
# under the parent-node, not displaying the list itself in
# the hierarchy.
def visit_Node(self, node):
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)))
self.indent()
self.visitchildren(node)
self.unindent()
return node
def repr_of(self, node):
if node is None:
return "(none)"
else:
result = node.__class__.__name__
if isinstance(node, ExprNodes.NameNode):
result += "(type=%s, name=\"%s\")" % (repr(node.type), node.name)
elif isinstance(node, Nodes.DefNode):
result += "(name=\"%s\")" % node.name
elif isinstance(node, ExprNodes.ExprNode):
t = node.type
result += "(type=%s)" % repr(t)
elif node.pos:
pos = node.pos
path = pos[0].get_description()
if '/' in path:
path = path.split('/')[-1]
if '\\' in path:
path = path.split('\\')[-1]
result += "(pos=(%s:%s:%s))" % (path, pos[1], pos[2])
return result
if __name__ == "__main__":
import doctest
doctest.testmod()
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Compiler/__init__.py 0000664 0000000 0000000 00000000000 11446142532 0025061 0 ustar 00root root 0000000 0000000 cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Debugger/ 0000775 0000000 0000000 00000000000 11446142532 0022734 5 ustar 00root root 0000000 0000000 cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Debugger/__init__.py 0000664 0000000 0000000 00000000000 11446142532 0025033 0 ustar 00root root 0000000 0000000 cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Debugger/cygdb.py 0000664 0000000 0000000 00000003120 11446142532 0024372 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python
"""
The Cython debugger
The current directory should contain a directory named 'cython_debug', or a
path to the cython project directory should be given (the parent directory of
cython_debug).
"""
import os
import sys
import glob
import tempfile
import subprocess
def main(import_libpython=False, path_to_debug_info=os.curdir):
"""
Start the Cython debugger. This tells gdb to import the Cython and Python
extensions (libpython.py and libcython.py) and it enables gdb's pending
breakpoints
import_libpython indicates whether we should just 'import libpython',
or import it from Cython.Debugger
path_to_debug_info is the path to the cython_debug directory
"""
debug_files = glob.glob(
os.path.join(path_to_debug_info, 'cython_debug/cython_debug_info_*'))
if not debug_files:
sys.exit('No debug files were found in %s. Aborting.' % (
os.path.abspath(path_to_debug_info)))
fd, tempfilename = tempfile.mkstemp()
f = os.fdopen(fd, 'w')
f.write('set breakpoint pending on\n')
f.write('python from Cython.Debugger import libcython\n')
if import_libpython:
f.write('python import libpython')
else:
f.write('python from Cython.Debugger import libpython\n')
f.write('\n'.join('cy import %s\n' % fn for fn in debug_files))
f.close()
p = subprocess.Popen(['gdb', '-command', tempfilename])
while True:
try:
p.wait()
except KeyboardInterrupt:
pass
else:
break
os.remove(tempfilename) cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Debugger/libcython.py 0000664 0000000 0000000 00000027044 11446142532 0025310 0 ustar 00root root 0000000 0000000 """
GDB extension that adds Cython support.
"""
import sys
import traceback
import functools
import itertools
import collections
import gdb
try:
from lxml import etree
have_lxml = True
except ImportError:
have_lxml = False
try:
# Python 2.5
from xml.etree import cElementTree as etree
except ImportError:
try:
# Python 2.5
from xml.etree import ElementTree as etree
except ImportError:
try:
# normal cElementTree install
import cElementTree as etree
except ImportError:
# normal ElementTree install
import elementtree.ElementTree as etree
if hasattr(gdb, 'string_to_argv'):
from gdb import string_to_argv
else:
from shlex import split as string_to_argv
from Cython.Debugger import libpython
# Cython module namespace
cython_namespace = {}
# C or Python type
CObject = object()
PythonObject = object()
# maps (unique) qualified function names (e.g.
# cythonmodule.ClassName.method_name) to the CythonFunction object
functions_by_qualified_name = {}
# unique cnames of Cython functions
functions_by_cname = {}
# map function names like method_name to a list of all such CythonFunction
# objects
functions_by_name = collections.defaultdict(list)
_filesystemencoding = sys.getfilesystemencoding() or 'UTF-8'
def dont_suppress_errors(function):
@functools.wraps(function)
def wrapper(*args, **kwargs):
try:
return function(*args, **kwargs)
except Exception:
traceback.print_exc()
raise
return wrapper
class CythonModule(object):
def __init__(self, module_name, filename):
self.name = module_name
self.filename = filename
self.functions = {}
self.globals = {}
class CythonVariable(object):
def __init__(self, name, cname, qualified_name, type):
self.name = name
self.cname = cname
self.qualified_name = qualified_name
self.type = type
class CythonFunction(CythonVariable):
def __init__(self,
module,
name,
cname,
pf_cname,
qualified_name,
lineno,
type=CObject):
super(CythonFunction, self).__init__(name, cname, qualified_name, type)
self.module = module
self.pf_cname = pf_cname
self.lineno = lineno
self.locals = {}
self.arguments = []
class CythonCommand(gdb.Command):
"""
Invoke a Cython command. Available commands are:
cy import
cy break
cy condition
cy step
cy enable
cy disable
cy print
cy list
cy locals
cy globals
cy tb
cy cname
"""
CythonCommand('cy', gdb.COMMAND_NONE, gdb.COMPLETE_COMMAND, prefix=True)
class CyImport(gdb.Command):
"""
Import debug information outputted by the Cython compiler
Example: cy import FILE...
"""
def invoke(self, args, from_tty):
args = args.encode(_filesystemencoding)
for arg in string_to_argv(args):
try:
f = open(arg)
except OSError, e:
print('Unable to open file %r: %s' % (args, e.args[1]))
return
t = etree.parse(f)
for module in t.getroot():
cython_module = CythonModule(**module.attrib)
cython_namespace[cython_module.name] = cython_module
for variable in module.find('Globals'):
d = variable.attrib
cython_module.globals[d['name']] = CythonVariable(**d)
for function in module.find('Functions'):
cython_function = CythonFunction(module=cython_module,
**function.attrib)
cython_module.functions[cython_function.name] = \
cython_function
# update the global function mappings
functions_by_name[cython_function.name].append(
cython_function)
functions_by_qualified_name[
cython_function.qualified_name] = cython_function
functions_by_cname[cython_function.cname] = cython_function
for local in function.find('Locals'):
d = local.attrib
cython_function.locals[d['name']] = CythonVariable(**d)
cython_function.arguments.extend(
funcarg.tag for funcarg in function.find('Arguments'))
CyImport('cy import', gdb.COMMAND_STATUS, gdb.COMPLETE_FILENAME)
class CyBreak(gdb.Command):
"""
Set a breakpoint for Cython code using Cython qualified name notation, e.g.:
cy-break cython_modulename.ClassName.method_name...
or normal notation:
cy-break function_or_method_name...
"""
def invoke(self, function_names, from_tty):
for funcname in string_to_argv(function_names.encode('UTF-8')):
func = functions_by_qualified_name.get(funcname)
break_funcs = [func]
if not func:
funcs = functions_by_name.get(funcname)
if not funcs:
gdb.execute('break ' + funcname)
return
if len(funcs) > 1:
# multiple functions, let the user pick one
print 'There are multiple such functions:'
for idx, func in enumerate(funcs):
print '%3d) %s' % (idx, func.qualified_name)
while True:
try:
result = raw_input(
"Select a function, press 'a' for all "
"functions or press 'q' or '^D' to quit: ")
except EOFError:
return
else:
if result.lower() == 'q':
return
elif result.lower() == 'a':
break_funcs = funcs
break
elif (result.isdigit() and
0 <= int(result) < len(funcs)):
break_funcs = [funcs[int(result)]]
break
else:
print 'Not understood...'
else:
break_funcs = [funcs[0]]
for func in break_funcs:
gdb.execute('break %s' % func.cname)
if func.pf_cname:
gdb.execute('break %s' % func.pf_cname)
@dont_suppress_errors
def complete(self, text, word):
names = itertools.chain(functions_by_qualified_name, functions_by_name)
words = text.strip().split()
if words and '.' in words[-1]:
compl = [n for n in functions_by_qualified_name
if n.startswith(lastword)]
else:
seen = set(text[:-len(word)].split())
return [n for n in names if n.startswith(word) and n not in seen]
if len(lastword) > len(word):
# readline sees something (e.g. a '.') as a word boundary, so don't
# "recomplete" this prefix
strip_prefix_length = len(lastword) - len(word)
compl = [n[strip_prefix_length:] for n in compl]
return compl
CyBreak('cy break', gdb.COMMAND_BREAKPOINTS)
# This needs GDB 7.2 or the Archer branch
# class CompleteUnqualifiedFunctionNames(gdb.Parameter):
# """
# Indicates whether 'cy break' should complete unqualified function or
# method names. e.g. whether only 'modulename.functioname' should be
# completed, or also just 'functionname'
# """
#
# cy_complete_unqualified = CompleteUnqualifiedFunctionNames(
# 'cy_complete_unqualified',
# gdb.COMMAND_BREAKPOINTS,
# gdb.PARAM_BOOLEAN)
class NoCythonFunctionNameInFrameError(Exception):
"""
raised when the name of the C function could not be determined
in the current C stack frame
"""
class CyPrint(gdb.Command):
"""
Print a Cython variable using 'cy-print x' or 'cy-print module.function.x'
"""
def _get_current_cython_function(self):
func_name = gdb.selected_frame().name()
if func_name is None:
raise NoCythonFunctionNameInFrameError()
return functions_by_cname.get(func_name)
def _get_locals_globals(self):
try:
cython_function = self._get_current_cython_function()
except NoCythonFunctionNameInFrameError:
return (None, None)
else:
if cython_function is None:
return (None, None)
return cython_function.locals, cython_function.module.globals
def invoke(self, name, from_tty):
try:
cython_function = self._get_current_cython_function()
except NoCythonFunctionNameInFrameError:
print('Unable to determine the name of the function in the '
'current frame.')
except RuntimeError, e:
print e.args[0]
else:
# a cython_function of None means we don't know about such a Cython
# function and we fall back to GDB's print
cname = name
if cython_function is not None:
if name in cython_function.locals:
cname = cython_function.locals[name].cname
elif name in cython_function.module.globals:
cname = cython_function.module.globals[name].cname
gdb.execute('print ' + cname)
def complete(self):
locals_, globals_ = self._get_locals_globals()
if locals_ is None:
return []
return list(itertools.chain(locals_, globals_))
CyPrint('cy print', gdb.COMMAND_DATA)
class CyLocals(CyPrint):
def ns(self):
locals_, _ = self._get_locals_globals()
return locals_
def invoke(self, name, from_tty):
try:
ns = self.ns()
except RuntimeError, e:
print e.args[0]
return
if ns is None:
print ('Information of Cython locals could not be obtained. '
'Is this an actual Cython function and did you '
"'cy import' the debug information?")
for var in ns.itervalues():
val = gdb.parse_and_eval(var.cname)
if var.type == PythonObject:
result = libpython.PyObjectPtr.from_pyobject_ptr(val)
else:
result = CObject
print '%s = %s' % (var.name, result)
class CyGlobals(CyLocals):
def ns(self):
_, globals_ = self._get_locals_globals()
return globals_
def invoke(self, name, from_tty):
m = gdb.parse_and_eval('PyModule_GetDict(__pyx_m)')
m = m.cast(gdb.lookup_type('PyModuleObject').pointer())
print PyObjectPtrPrinter(libpython.PyObjectPtr.from_pyobject_ptr(m['md_dict'])).to_string()
CyLocals('cy locals', gdb.COMMAND_STACK, gdb.COMPLETE_NONE)
CyGlobals('cy globals', gdb.COMMAND_STACK, gdb.COMPLETE_NONE)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Debugger/libpython.py 0000664 0000000 0000000 00000133703 11446142532 0025325 0 ustar 00root root 0000000 0000000 #!/usr/bin/python
'''
From gdb 7 onwards, gdb's build can be configured --with-python, allowing gdb
to be extended with Python code e.g. for library-specific data visualizations,
such as for the C++ STL types. Documentation on this API can be seen at:
http://sourceware.org/gdb/current/onlinedocs/gdb/Python-API.html
This python module deals with the case when the process being debugged (the
"inferior process" in gdb parlance) is itself python, or more specifically,
linked against libpython. In this situation, almost every item of data is a
(PyObject*), and having the debugger merely print their addresses is not very
enlightening.
This module embeds knowledge about the implementation details of libpython so
that we can emit useful visualizations e.g. a string, a list, a dict, a frame
giving file/line information and the state of local variables
In particular, given a gdb.Value corresponding to a PyObject* in the inferior
process, we can generate a "proxy value" within the gdb process. For example,
given a PyObject* in the inferior process that is in fact a PyListObject*
holding three PyObject* that turn out to be PyStringObject* instances, we can
generate a proxy value within the gdb process that is a list of strings:
["foo", "bar", "baz"]
Doing so can be expensive for complicated graphs of objects, and could take
some time, so we also have a "write_repr" method that writes a representation
of the data to a file-like object. This allows us to stop the traversal by
having the file-like object raise an exception if it gets too much data.
With both "proxyval" and "write_repr" we keep track of the set of all addresses
visited so far in the traversal, to avoid infinite recursion due to cycles in
the graph of object references.
We try to defer gdb.lookup_type() invocations for python types until as late as
possible: for a dynamically linked python binary, when the process starts in
the debugger, the libpython.so hasn't been dynamically loaded yet, so none of
the type names are known to the debugger
The module also extends gdb with some python-specific commands.
'''
from __future__ import with_statement
import gdb
# Look up the gdb.Type for some standard types:
_type_char_ptr = gdb.lookup_type('char').pointer() # char*
_type_unsigned_char_ptr = gdb.lookup_type('unsigned char').pointer() # unsigned char*
_type_void_ptr = gdb.lookup_type('void').pointer() # void*
SIZEOF_VOID_P = _type_void_ptr.sizeof
Py_TPFLAGS_HEAPTYPE = (1L << 9)
Py_TPFLAGS_INT_SUBCLASS = (1L << 23)
Py_TPFLAGS_LONG_SUBCLASS = (1L << 24)
Py_TPFLAGS_LIST_SUBCLASS = (1L << 25)
Py_TPFLAGS_TUPLE_SUBCLASS = (1L << 26)
Py_TPFLAGS_STRING_SUBCLASS = (1L << 27)
Py_TPFLAGS_UNICODE_SUBCLASS = (1L << 28)
Py_TPFLAGS_DICT_SUBCLASS = (1L << 29)
Py_TPFLAGS_BASE_EXC_SUBCLASS = (1L << 30)
Py_TPFLAGS_TYPE_SUBCLASS = (1L << 31)
MAX_OUTPUT_LEN=1024
class NullPyObjectPtr(RuntimeError):
pass
def safety_limit(val):
# Given a integer value from the process being debugged, limit it to some
# safety threshold so that arbitrary breakage within said process doesn't
# break the gdb process too much (e.g. sizes of iterations, sizes of lists)
return min(val, 1000)
def safe_range(val):
# As per range, but don't trust the value too much: cap it to a safety
# threshold in case the data was corrupted
return xrange(safety_limit(val))
class StringTruncated(RuntimeError):
pass
class TruncatedStringIO(object):
'''Similar to cStringIO, but can truncate the output by raising a
StringTruncated exception'''
def __init__(self, maxlen=None):
self._val = ''
self.maxlen = maxlen
def write(self, data):
if self.maxlen:
if len(data) + len(self._val) > self.maxlen:
# Truncation:
self._val += data[0:self.maxlen - len(self._val)]
raise StringTruncated()
self._val += data
def getvalue(self):
return self._val
class PyObjectPtr(object):
"""
Class wrapping a gdb.Value that's a either a (PyObject*) within the
inferior process, or some subclass pointer e.g. (PyStringObject*)
There will be a subclass for every refined PyObject type that we care
about.
Note that at every stage the underlying pointer could be NULL, point
to corrupt data, etc; this is the debugger, after all.
"""
_typename = 'PyObject'
def __init__(self, gdbval, cast_to=None):
if cast_to:
self._gdbval = gdbval.cast(cast_to)
else:
self._gdbval = gdbval
def field(self, name):
'''
Get the gdb.Value for the given field within the PyObject, coping with
some python 2 versus python 3 differences.
Various libpython types are defined using the "PyObject_HEAD" and
"PyObject_VAR_HEAD" macros.
In Python 2, this these are defined so that "ob_type" and (for a var
object) "ob_size" are fields of the type in question.
In Python 3, this is defined as an embedded PyVarObject type thus:
PyVarObject ob_base;
so that the "ob_size" field is located insize the "ob_base" field, and
the "ob_type" is most easily accessed by casting back to a (PyObject*).
'''
if self.is_null():
raise NullPyObjectPtr(self)
if name == 'ob_type':
pyo_ptr = self._gdbval.cast(PyObjectPtr.get_gdb_type())
return pyo_ptr.dereference()[name]
if name == 'ob_size':
try:
# Python 2:
return self._gdbval.dereference()[name]
except RuntimeError:
# Python 3:
return self._gdbval.dereference()['ob_base'][name]
# General case: look it up inside the object:
return self._gdbval.dereference()[name]
def pyop_field(self, name):
'''
Get a PyObjectPtr for the given PyObject* field within this PyObject,
coping with some python 2 versus python 3 differences.
'''
return PyObjectPtr.from_pyobject_ptr(self.field(name))
def write_field_repr(self, name, out, visited):
'''
Extract the PyObject* field named "name", and write its representation
to file-like object "out"
'''
field_obj = self.pyop_field(name)
field_obj.write_repr(out, visited)
def get_truncated_repr(self, maxlen):
'''
Get a repr-like string for the data, but truncate it at "maxlen" bytes
(ending the object graph traversal as soon as you do)
'''
out = TruncatedStringIO(maxlen)
try:
self.write_repr(out, set())
except StringTruncated:
# Truncation occurred:
return out.getvalue() + '...(truncated)'
# No truncation occurred:
return out.getvalue()
def type(self):
return PyTypeObjectPtr(self.field('ob_type'))
def is_null(self):
return 0 == long(self._gdbval)
def is_optimized_out(self):
'''
Is the value of the underlying PyObject* visible to the debugger?
This can vary with the precise version of the compiler used to build
Python, and the precise version of gdb.
See e.g. https://bugzilla.redhat.com/show_bug.cgi?id=556975 with
PyEval_EvalFrameEx's "f"
'''
return self._gdbval.is_optimized_out
def safe_tp_name(self):
try:
return self.type().field('tp_name').string()
except NullPyObjectPtr:
# NULL tp_name?
return 'unknown'
except RuntimeError:
# Can't even read the object at all?
return 'unknown'
def proxyval(self, visited):
'''
Scrape a value from the inferior process, and try to represent it
within the gdb process, whilst (hopefully) avoiding crashes when
the remote data is corrupt.
Derived classes will override this.
For example, a PyIntObject* with ob_ival 42 in the inferior process
should result in an int(42) in this process.
visited: a set of all gdb.Value pyobject pointers already visited
whilst generating this value (to guard against infinite recursion when
visiting object graphs with loops). Analogous to Py_ReprEnter and
Py_ReprLeave
'''
class FakeRepr(object):
"""
Class representing a non-descript PyObject* value in the inferior
process for when we don't have a custom scraper, intended to have
a sane repr().
"""
def __init__(self, tp_name, address):
self.tp_name = tp_name
self.address = address
def __repr__(self):
# For the NULL pointer, we have no way of knowing a type, so
# special-case it as per
# http://bugs.python.org/issue8032#msg100882
if self.address == 0:
return '0x0'
return '<%s at remote 0x%x>' % (self.tp_name, self.address)
return FakeRepr(self.safe_tp_name(),
long(self._gdbval))
def write_repr(self, out, visited):
'''
Write a string representation of the value scraped from the inferior
process to "out", a file-like object.
'''
# Default implementation: generate a proxy value and write its repr
# However, this could involve a lot of work for complicated objects,
# so for derived classes we specialize this
return out.write(repr(self.proxyval(visited)))
@classmethod
def subclass_from_type(cls, t):
'''
Given a PyTypeObjectPtr instance wrapping a gdb.Value that's a
(PyTypeObject*), determine the corresponding subclass of PyObjectPtr
to use
Ideally, we would look up the symbols for the global types, but that
isn't working yet:
(gdb) python print gdb.lookup_symbol('PyList_Type')[0].value
Traceback (most recent call last):
File "", line 1, in
NotImplementedError: Symbol type not yet supported in Python scripts.
Error while executing Python code.
For now, we use tp_flags, after doing some string comparisons on the
tp_name for some special-cases that don't seem to be visible through
flags
'''
try:
tp_name = t.field('tp_name').string()
tp_flags = int(t.field('tp_flags'))
except RuntimeError:
# Handle any kind of error e.g. NULL ptrs by simply using the base
# class
return cls
#print 'tp_flags = 0x%08x' % tp_flags
#print 'tp_name = %r' % tp_name
name_map = {'bool': PyBoolObjectPtr,
'classobj': PyClassObjectPtr,
'instance': PyInstanceObjectPtr,
'NoneType': PyNoneStructPtr,
'frame': PyFrameObjectPtr,
'set' : PySetObjectPtr,
'frozenset' : PySetObjectPtr,
'builtin_function_or_method' : PyCFunctionObjectPtr,
}
if tp_name in name_map:
return name_map[tp_name]
if tp_flags & Py_TPFLAGS_HEAPTYPE:
return HeapTypeObjectPtr
if tp_flags & Py_TPFLAGS_INT_SUBCLASS:
return PyIntObjectPtr
if tp_flags & Py_TPFLAGS_LONG_SUBCLASS:
return PyLongObjectPtr
if tp_flags & Py_TPFLAGS_LIST_SUBCLASS:
return PyListObjectPtr
if tp_flags & Py_TPFLAGS_TUPLE_SUBCLASS:
return PyTupleObjectPtr
if tp_flags & Py_TPFLAGS_STRING_SUBCLASS:
return PyStringObjectPtr
if tp_flags & Py_TPFLAGS_UNICODE_SUBCLASS:
return PyUnicodeObjectPtr
if tp_flags & Py_TPFLAGS_DICT_SUBCLASS:
return PyDictObjectPtr
if tp_flags & Py_TPFLAGS_BASE_EXC_SUBCLASS:
return PyBaseExceptionObjectPtr
#if tp_flags & Py_TPFLAGS_TYPE_SUBCLASS:
# return PyTypeObjectPtr
# Use the base class:
return cls
@classmethod
def from_pyobject_ptr(cls, gdbval):
'''
Try to locate the appropriate derived class dynamically, and cast
the pointer accordingly.
'''
try:
p = PyObjectPtr(gdbval)
cls = cls.subclass_from_type(p.type())
return cls(gdbval, cast_to=cls.get_gdb_type())
except RuntimeError:
# Handle any kind of error e.g. NULL ptrs by simply using the base
# class
pass
return cls(gdbval)
@classmethod
def get_gdb_type(cls):
return gdb.lookup_type(cls._typename).pointer()
def as_address(self):
return long(self._gdbval)
class ProxyAlreadyVisited(object):
'''
Placeholder proxy to use when protecting against infinite recursion due to
loops in the object graph.
Analogous to the values emitted by the users of Py_ReprEnter and Py_ReprLeave
'''
def __init__(self, rep):
self._rep = rep
def __repr__(self):
return self._rep
def _write_instance_repr(out, visited, name, pyop_attrdict, address):
'''Shared code for use by old-style and new-style classes:
write a representation to file-like object "out"'''
out.write('<')
out.write(name)
# Write dictionary of instance attributes:
if isinstance(pyop_attrdict, PyDictObjectPtr):
out.write('(')
first = True
for pyop_arg, pyop_val in pyop_attrdict.iteritems():
if not first:
out.write(', ')
first = False
out.write(pyop_arg.proxyval(visited))
out.write('=')
pyop_val.write_repr(out, visited)
out.write(')')
out.write(' at remote 0x%x>' % address)
class InstanceProxy(object):
def __init__(self, cl_name, attrdict, address):
self.cl_name = cl_name
self.attrdict = attrdict
self.address = address
def __repr__(self):
if isinstance(self.attrdict, dict):
kwargs = ', '.join(["%s=%r" % (arg, val)
for arg, val in self.attrdict.iteritems()])
return '<%s(%s) at remote 0x%x>' % (self.cl_name,
kwargs, self.address)
else:
return '<%s at remote 0x%x>' % (self.cl_name,
self.address)
def _PyObject_VAR_SIZE(typeobj, nitems):
return ( ( typeobj.field('tp_basicsize') +
nitems * typeobj.field('tp_itemsize') +
(SIZEOF_VOID_P - 1)
) & ~(SIZEOF_VOID_P - 1)
).cast(gdb.lookup_type('size_t'))
class HeapTypeObjectPtr(PyObjectPtr):
_typename = 'PyObject'
def get_attr_dict(self):
'''
Get the PyDictObject ptr representing the attribute dictionary
(or None if there's a problem)
'''
try:
typeobj = self.type()
dictoffset = int_from_int(typeobj.field('tp_dictoffset'))
if dictoffset != 0:
if dictoffset < 0:
type_PyVarObject_ptr = gdb.lookup_type('PyVarObject').pointer()
tsize = int_from_int(self._gdbval.cast(type_PyVarObject_ptr)['ob_size'])
if tsize < 0:
tsize = -tsize
size = _PyObject_VAR_SIZE(typeobj, tsize)
dictoffset += size
assert dictoffset > 0
assert dictoffset % SIZEOF_VOID_P == 0
dictptr = self._gdbval.cast(_type_char_ptr) + dictoffset
PyObjectPtrPtr = PyObjectPtr.get_gdb_type().pointer()
dictptr = dictptr.cast(PyObjectPtrPtr)
return PyObjectPtr.from_pyobject_ptr(dictptr.dereference())
except RuntimeError:
# Corrupt data somewhere; fail safe
pass
# Not found, or some kind of error:
return None
def proxyval(self, visited):
'''
Support for new-style classes.
Currently we just locate the dictionary using a transliteration to
python of _PyObject_GetDictPtr, ignoring descriptors
'''
# Guard against infinite loops:
if self.as_address() in visited:
return ProxyAlreadyVisited('<...>')
visited.add(self.as_address())
pyop_attr_dict = self.get_attr_dict()
if pyop_attr_dict:
attr_dict = pyop_attr_dict.proxyval(visited)
else:
attr_dict = {}
tp_name = self.safe_tp_name()
# New-style class:
return InstanceProxy(tp_name, attr_dict, long(self._gdbval))
def write_repr(self, out, visited):
# Guard against infinite loops:
if self.as_address() in visited:
out.write('<...>')
return
visited.add(self.as_address())
pyop_attrdict = self.get_attr_dict()
_write_instance_repr(out, visited,
self.safe_tp_name(), pyop_attrdict, self.as_address())
class ProxyException(Exception):
def __init__(self, tp_name, args):
self.tp_name = tp_name
self.args = args
def __repr__(self):
return '%s%r' % (self.tp_name, self.args)
class PyBaseExceptionObjectPtr(PyObjectPtr):
"""
Class wrapping a gdb.Value that's a PyBaseExceptionObject* i.e. an exception
within the process being debugged.
"""
_typename = 'PyBaseExceptionObject'
def proxyval(self, visited):
# Guard against infinite loops:
if self.as_address() in visited:
return ProxyAlreadyVisited('(...)')
visited.add(self.as_address())
arg_proxy = self.pyop_field('args').proxyval(visited)
return ProxyException(self.safe_tp_name(),
arg_proxy)
def write_repr(self, out, visited):
# Guard against infinite loops:
if self.as_address() in visited:
out.write('(...)')
return
visited.add(self.as_address())
out.write(self.safe_tp_name())
self.write_field_repr('args', out, visited)
class PyBoolObjectPtr(PyObjectPtr):
"""
Class wrapping a gdb.Value that's a PyBoolObject* i.e. one of the two
instances (Py_True/Py_False) within the process being debugged.
"""
_typename = 'PyBoolObject'
def proxyval(self, visited):
if int_from_int(self.field('ob_ival')):
return True
else:
return False
class PyClassObjectPtr(PyObjectPtr):
"""
Class wrapping a gdb.Value that's a PyClassObject* i.e. a
instance within the process being debugged.
"""
_typename = 'PyClassObject'
class BuiltInFunctionProxy(object):
def __init__(self, ml_name):
self.ml_name = ml_name
def __repr__(self):
return "" % self.ml_name
class BuiltInMethodProxy(object):
def __init__(self, ml_name, pyop_m_self):
self.ml_name = ml_name
self.pyop_m_self = pyop_m_self
def __repr__(self):
return (''
% (self.ml_name,
self.pyop_m_self.safe_tp_name(),
self.pyop_m_self.as_address())
)
class PyCFunctionObjectPtr(PyObjectPtr):
"""
Class wrapping a gdb.Value that's a PyCFunctionObject*
(see Include/methodobject.h and Objects/methodobject.c)
"""
_typename = 'PyCFunctionObject'
def proxyval(self, visited):
m_ml = self.field('m_ml') # m_ml is a (PyMethodDef*)
ml_name = m_ml['ml_name'].string()
pyop_m_self = self.pyop_field('m_self')
if pyop_m_self.is_null():
return BuiltInFunctionProxy(ml_name)
else:
return BuiltInMethodProxy(ml_name, pyop_m_self)
class PyCodeObjectPtr(PyObjectPtr):
"""
Class wrapping a gdb.Value that's a PyCodeObject* i.e. a instance
within the process being debugged.
"""
_typename = 'PyCodeObject'
def addr2line(self, addrq):
'''
Get the line number for a given bytecode offset
Analogous to PyCode_Addr2Line; translated from pseudocode in
Objects/lnotab_notes.txt
'''
co_lnotab = self.pyop_field('co_lnotab').proxyval(set())
# Initialize lineno to co_firstlineno as per PyCode_Addr2Line
# not 0, as lnotab_notes.txt has it:
lineno = int_from_int(self.field('co_firstlineno'))
addr = 0
for addr_incr, line_incr in zip(co_lnotab[::2], co_lnotab[1::2]):
addr += ord(addr_incr)
if addr > addrq:
return lineno
lineno += ord(line_incr)
return lineno
class PyDictObjectPtr(PyObjectPtr):
"""
Class wrapping a gdb.Value that's a PyDictObject* i.e. a dict instance
within the process being debugged.
"""
_typename = 'PyDictObject'
def iteritems(self):
'''
Yields a sequence of (PyObjectPtr key, PyObjectPtr value) pairs,
analagous to dict.iteritems()
'''
for i in safe_range(self.field('ma_mask') + 1):
ep = self.field('ma_table') + i
pyop_value = PyObjectPtr.from_pyobject_ptr(ep['me_value'])
if not pyop_value.is_null():
pyop_key = PyObjectPtr.from_pyobject_ptr(ep['me_key'])
yield (pyop_key, pyop_value)
def proxyval(self, visited):
# Guard against infinite loops:
if self.as_address() in visited:
return ProxyAlreadyVisited('{...}')
visited.add(self.as_address())
result = {}
for pyop_key, pyop_value in self.iteritems():
proxy_key = pyop_key.proxyval(visited)
proxy_value = pyop_value.proxyval(visited)
result[proxy_key] = proxy_value
return result
def write_repr(self, out, visited):
# Guard against infinite loops:
if self.as_address() in visited:
out.write('{...}')
return
visited.add(self.as_address())
out.write('{')
first = True
for pyop_key, pyop_value in self.iteritems():
if not first:
out.write(', ')
first = False
pyop_key.write_repr(out, visited)
out.write(': ')
pyop_value.write_repr(out, visited)
out.write('}')
class PyInstanceObjectPtr(PyObjectPtr):
_typename = 'PyInstanceObject'
def proxyval(self, visited):
# Guard against infinite loops:
if self.as_address() in visited:
return ProxyAlreadyVisited('<...>')
visited.add(self.as_address())
# Get name of class:
in_class = self.pyop_field('in_class')
cl_name = in_class.pyop_field('cl_name').proxyval(visited)
# Get dictionary of instance attributes:
in_dict = self.pyop_field('in_dict').proxyval(visited)
# Old-style class:
return InstanceProxy(cl_name, in_dict, long(self._gdbval))
def write_repr(self, out, visited):
# Guard against infinite loops:
if self.as_address() in visited:
out.write('<...>')
return
visited.add(self.as_address())
# Old-style class:
# Get name of class:
in_class = self.pyop_field('in_class')
cl_name = in_class.pyop_field('cl_name').proxyval(visited)
# Get dictionary of instance attributes:
pyop_in_dict = self.pyop_field('in_dict')
_write_instance_repr(out, visited,
cl_name, pyop_in_dict, self.as_address())
class PyIntObjectPtr(PyObjectPtr):
_typename = 'PyIntObject'
def proxyval(self, visited):
result = int_from_int(self.field('ob_ival'))
return result
class PyListObjectPtr(PyObjectPtr):
_typename = 'PyListObject'
def __getitem__(self, i):
# Get the gdb.Value for the (PyObject*) with the given index:
field_ob_item = self.field('ob_item')
return field_ob_item[i]
def proxyval(self, visited):
# Guard against infinite loops:
if self.as_address() in visited:
return ProxyAlreadyVisited('[...]')
visited.add(self.as_address())
result = [PyObjectPtr.from_pyobject_ptr(self[i]).proxyval(visited)
for i in safe_range(int_from_int(self.field('ob_size')))]
return result
def write_repr(self, out, visited):
# Guard against infinite loops:
if self.as_address() in visited:
out.write('[...]')
return
visited.add(self.as_address())
out.write('[')
for i in safe_range(int_from_int(self.field('ob_size'))):
if i > 0:
out.write(', ')
element = PyObjectPtr.from_pyobject_ptr(self[i])
element.write_repr(out, visited)
out.write(']')
class PyLongObjectPtr(PyObjectPtr):
_typename = 'PyLongObject'
def proxyval(self, visited):
'''
Python's Include/longobjrep.h has this declaration:
struct _longobject {
PyObject_VAR_HEAD
digit ob_digit[1];
};
with this description:
The absolute value of a number is equal to
SUM(for i=0 through abs(ob_size)-1) ob_digit[i] * 2**(SHIFT*i)
Negative numbers are represented with ob_size < 0;
zero is represented by ob_size == 0.
where SHIFT can be either:
#define PyLong_SHIFT 30
#define PyLong_SHIFT 15
'''
ob_size = long(self.field('ob_size'))
if ob_size == 0:
return 0L
ob_digit = self.field('ob_digit')
if gdb.lookup_type('digit').sizeof == 2:
SHIFT = 15L
else:
SHIFT = 30L
digits = [long(ob_digit[i]) * 2**(SHIFT*i)
for i in safe_range(abs(ob_size))]
result = sum(digits)
if ob_size < 0:
result = -result
return result
class PyNoneStructPtr(PyObjectPtr):
"""
Class wrapping a gdb.Value that's a PyObject* pointing to the
singleton (we hope) _Py_NoneStruct with ob_type PyNone_Type
"""
_typename = 'PyObject'
def proxyval(self, visited):
return None
class PyFrameObjectPtr(PyObjectPtr):
_typename = 'PyFrameObject'
def __init__(self, gdbval, cast_to):
PyObjectPtr.__init__(self, gdbval, cast_to)
if not self.is_optimized_out():
self.co = PyCodeObjectPtr.from_pyobject_ptr(self.field('f_code'))
self.co_name = self.co.pyop_field('co_name')
self.co_filename = self.co.pyop_field('co_filename')
self.f_lineno = int_from_int(self.field('f_lineno'))
self.f_lasti = int_from_int(self.field('f_lasti'))
self.co_nlocals = int_from_int(self.co.field('co_nlocals'))
self.co_varnames = PyTupleObjectPtr.from_pyobject_ptr(self.co.field('co_varnames'))
def iter_locals(self):
'''
Yield a sequence of (name,value) pairs of PyObjectPtr instances, for
the local variables of this frame
'''
if self.is_optimized_out():
return
f_localsplus = self.field('f_localsplus')
for i in safe_range(self.co_nlocals):
pyop_value = PyObjectPtr.from_pyobject_ptr(f_localsplus[i])
if not pyop_value.is_null():
pyop_name = PyObjectPtr.from_pyobject_ptr(self.co_varnames[i])
yield (pyop_name, pyop_value)
def iter_globals(self):
'''
Yield a sequence of (name,value) pairs of PyObjectPtr instances, for
the global variables of this frame
'''
if self.is_optimized_out():
return
pyop_globals = self.pyop_field('f_globals')
return pyop_globals.iteritems()
def iter_builtins(self):
'''
Yield a sequence of (name,value) pairs of PyObjectPtr instances, for
the builtin variables
'''
if self.is_optimized_out():
return
pyop_builtins = self.pyop_field('f_builtins')
return pyop_builtins.iteritems()
def get_var_by_name(self, name):
'''
Look for the named local variable, returning a (PyObjectPtr, scope) pair
where scope is a string 'local', 'global', 'builtin'
If not found, return (None, None)
'''
for pyop_name, pyop_value in self.iter_locals():
if name == pyop_name.proxyval(set()):
return pyop_value, 'local'
for pyop_name, pyop_value in self.iter_globals():
if name == pyop_name.proxyval(set()):
return pyop_value, 'global'
for pyop_name, pyop_value in self.iter_builtins():
if name == pyop_name.proxyval(set()):
return pyop_value, 'builtin'
return None, None
def filename(self):
'''Get the path of the current Python source file, as a string'''
if self.is_optimized_out():
return '(frame information optimized out)'
return self.co_filename.proxyval(set())
def current_line_num(self):
'''Get current line number as an integer (1-based)
Translated from PyFrame_GetLineNumber and PyCode_Addr2Line
See Objects/lnotab_notes.txt
'''
if self.is_optimized_out():
return None
f_trace = self.field('f_trace')
if long(f_trace) != 0:
# we have a non-NULL f_trace:
return self.f_lineno
else:
#try:
return self.co.addr2line(self.f_lasti)
#except ValueError:
# return self.f_lineno
def current_line(self):
'''Get the text of the current source line as a string, with a trailing
newline character'''
if self.is_optimized_out():
return '(frame information optimized out)'
with open(self.filename(), 'r') as f:
all_lines = f.readlines()
# Convert from 1-based current_line_num to 0-based list offset:
return all_lines[self.current_line_num()-1]
def write_repr(self, out, visited):
if self.is_optimized_out():
out.write('(frame information optimized out)')
return
out.write('Frame 0x%x, for file %s, line %i, in %s ('
% (self.as_address(),
self.co_filename,
self.current_line_num(),
self.co_name))
first = True
for pyop_name, pyop_value in self.iter_locals():
if not first:
out.write(', ')
first = False
out.write(pyop_name.proxyval(visited))
out.write('=')
pyop_value.write_repr(out, visited)
out.write(')')
class PySetObjectPtr(PyObjectPtr):
_typename = 'PySetObject'
def proxyval(self, visited):
# Guard against infinite loops:
if self.as_address() in visited:
return ProxyAlreadyVisited('%s(...)' % self.safe_tp_name())
visited.add(self.as_address())
members = []
table = self.field('table')
for i in safe_range(self.field('mask')+1):
setentry = table[i]
key = setentry['key']
if key != 0:
key_proxy = PyObjectPtr.from_pyobject_ptr(key).proxyval(visited)
if key_proxy != '':
members.append(key_proxy)
if self.safe_tp_name() == 'frozenset':
return frozenset(members)
else:
return set(members)
def write_repr(self, out, visited):
out.write(self.safe_tp_name())
# Guard against infinite loops:
if self.as_address() in visited:
out.write('(...)')
return
visited.add(self.as_address())
out.write('([')
first = True
table = self.field('table')
for i in safe_range(self.field('mask')+1):
setentry = table[i]
key = setentry['key']
if key != 0:
pyop_key = PyObjectPtr.from_pyobject_ptr(key)
key_proxy = pyop_key.proxyval(visited) # FIXME!
if key_proxy != '':
if not first:
out.write(', ')
first = False
pyop_key.write_repr(out, visited)
out.write('])')
class PyStringObjectPtr(PyObjectPtr):
_typename = 'PyStringObject'
def __str__(self):
field_ob_size = self.field('ob_size')
field_ob_sval = self.field('ob_sval')
char_ptr = field_ob_sval.address.cast(_type_unsigned_char_ptr)
return ''.join([chr(char_ptr[i]) for i in safe_range(field_ob_size)])
def proxyval(self, visited):
return str(self)
class PyTupleObjectPtr(PyObjectPtr):
_typename = 'PyTupleObject'
def __getitem__(self, i):
# Get the gdb.Value for the (PyObject*) with the given index:
field_ob_item = self.field('ob_item')
return field_ob_item[i]
def proxyval(self, visited):
# Guard against infinite loops:
if self.as_address() in visited:
return ProxyAlreadyVisited('(...)')
visited.add(self.as_address())
result = tuple([PyObjectPtr.from_pyobject_ptr(self[i]).proxyval(visited)
for i in safe_range(int_from_int(self.field('ob_size')))])
return result
def write_repr(self, out, visited):
# Guard against infinite loops:
if self.as_address() in visited:
out.write('(...)')
return
visited.add(self.as_address())
out.write('(')
for i in safe_range(int_from_int(self.field('ob_size'))):
if i > 0:
out.write(', ')
element = PyObjectPtr.from_pyobject_ptr(self[i])
element.write_repr(out, visited)
if self.field('ob_size') == 1:
out.write(',)')
else:
out.write(')')
class PyTypeObjectPtr(PyObjectPtr):
_typename = 'PyTypeObject'
class PyUnicodeObjectPtr(PyObjectPtr):
_typename = 'PyUnicodeObject'
def char_width(self):
_type_Py_UNICODE = gdb.lookup_type('Py_UNICODE')
return _type_Py_UNICODE.sizeof
def proxyval(self, visited):
# From unicodeobject.h:
# Py_ssize_t length; /* Length of raw Unicode data in buffer */
# Py_UNICODE *str; /* Raw Unicode buffer */
field_length = long(self.field('length'))
field_str = self.field('str')
# Gather a list of ints from the Py_UNICODE array; these are either
# UCS-2 or UCS-4 code points:
Py_UNICODEs = [int(field_str[i]) for i in safe_range(field_length)]
# Convert the int code points to unicode characters, and generate a
# local unicode instance:
result = u''.join([unichr(ucs) for ucs in Py_UNICODEs])
return result
def write_repr(self, out, visited):
proxy = self.proxyval(visited)
if self.char_width() == 2:
# sizeof(Py_UNICODE)==2: join surrogates
proxy2 = []
i = 0
while i < len(proxy):
ch = proxy[i]
i += 1
if (i < len(proxy)
and 0xD800 <= ord(ch) < 0xDC00 \
and 0xDC00 <= ord(proxy[i]) <= 0xDFFF):
# Get code point from surrogate pair
ch2 = proxy[i]
code = (ord(ch) & 0x03FF) << 10
code |= ord(ch2) & 0x03FF
code += 0x00010000
i += 1
proxy2.append(unichr(code))
else:
proxy2.append(ch)
proxy = u''.join(proxy2)
out.write(repr(proxy))
def int_from_int(gdbval):
return int(str(gdbval))
def stringify(val):
# TODO: repr() puts everything on one line; pformat can be nicer, but
# can lead to v.long results; this function isolates the choice
if True:
return repr(val)
else:
from pprint import pformat
return pformat(val)
class PyObjectPtrPrinter:
"Prints a (PyObject*)"
def __init__ (self, gdbval):
self.gdbval = gdbval
def to_string (self):
pyop = PyObjectPtr.from_pyobject_ptr(self.gdbval)
if True:
return pyop.get_truncated_repr(MAX_OUTPUT_LEN)
else:
# Generate full proxy value then stringify it.
# Doing so could be expensive
proxyval = pyop.proxyval(set())
return stringify(proxyval)
def pretty_printer_lookup(gdbval):
type = gdbval.type.unqualified()
if type.code == gdb.TYPE_CODE_PTR:
type = type.target().unqualified()
t = str(type)
if t in ("PyObject", "PyFrameObject"):
return PyObjectPtrPrinter(gdbval)
"""
During development, I've been manually invoking the code in this way:
(gdb) python
import sys
sys.path.append('/home/david/coding/python-gdb')
import libpython
end
then reloading it after each edit like this:
(gdb) python reload(libpython)
The following code should ensure that the prettyprinter is registered
if the code is autoloaded by gdb when visiting libpython.so, provided
that this python file is installed to the same path as the library (or its
.debug file) plus a "-gdb.py" suffix, e.g:
/usr/lib/libpython2.6.so.1.0-gdb.py
/usr/lib/debug/usr/lib/libpython2.6.so.1.0.debug-gdb.py
"""
def register (obj):
if obj == None:
obj = gdb
# Wire up the pretty-printer
obj.pretty_printers.append(pretty_printer_lookup)
register (gdb.current_objfile ())
# Unfortunately, the exact API exposed by the gdb module varies somewhat
# from build to build
# See http://bugs.python.org/issue8279?#msg102276
class Frame(object):
'''
Wrapper for gdb.Frame, adding various methods
'''
def __init__(self, gdbframe):
self._gdbframe = gdbframe
def older(self):
older = self._gdbframe.older()
if older:
return Frame(older)
else:
return None
def newer(self):
newer = self._gdbframe.newer()
if newer:
return Frame(newer)
else:
return None
def select(self):
'''If supported, select this frame and return True; return False if unsupported
Not all builds have a gdb.Frame.select method; seems to be present on Fedora 12
onwards, but absent on Ubuntu buildbot'''
if not hasattr(self._gdbframe, 'select'):
print ('Unable to select frame: '
'this build of gdb does not expose a gdb.Frame.select method')
return False
self._gdbframe.select()
return True
def get_index(self):
'''Calculate index of frame, starting at 0 for the newest frame within
this thread'''
index = 0
# Go down until you reach the newest frame:
iter_frame = self
while iter_frame.newer():
index += 1
iter_frame = iter_frame.newer()
return index
def is_evalframeex(self):
'''Is this a PyEval_EvalFrameEx frame?'''
if self._gdbframe.name() == 'PyEval_EvalFrameEx':
'''
I believe we also need to filter on the inline
struct frame_id.inline_depth, only regarding frames with
an inline depth of 0 as actually being this function
So we reject those with type gdb.INLINE_FRAME
'''
if self._gdbframe.type() == gdb.NORMAL_FRAME:
# We have a PyEval_EvalFrameEx frame:
return True
return False
def get_pyop(self):
try:
f = self._gdbframe.read_var('f')
return PyFrameObjectPtr.from_pyobject_ptr(f)
except ValueError:
return None
@classmethod
def get_selected_frame(cls):
_gdbframe = gdb.selected_frame()
if _gdbframe:
return Frame(_gdbframe)
return None
@classmethod
def get_selected_python_frame(cls):
'''Try to obtain the Frame for the python code in the selected frame,
or None'''
frame = cls.get_selected_frame()
while frame:
if frame.is_evalframeex():
return frame
frame = frame.older()
# Not found:
return None
def print_summary(self):
if self.is_evalframeex():
pyop = self.get_pyop()
if pyop:
sys.stdout.write('#%i %s\n' % (self.get_index(), pyop.get_truncated_repr(MAX_OUTPUT_LEN)))
sys.stdout.write(pyop.current_line())
else:
sys.stdout.write('#%i (unable to read python frame information)\n' % self.get_index())
else:
sys.stdout.write('#%i\n' % self.get_index())
class PyList(gdb.Command):
'''List the current Python source code, if any
Use
py-list START
to list at a different line number within the python source.
Use
py-list START, END
to list a specific range of lines within the python source.
'''
def __init__(self):
gdb.Command.__init__ (self,
"py-list",
gdb.COMMAND_FILES,
gdb.COMPLETE_NONE)
def invoke(self, args, from_tty):
import re
start = None
end = None
m = re.match(r'\s*(\d+)\s*', args)
if m:
start = int(m.group(0))
end = start + 10
m = re.match(r'\s*(\d+)\s*,\s*(\d+)\s*', args)
if m:
start, end = map(int, m.groups())
frame = Frame.get_selected_python_frame()
if not frame:
print 'Unable to locate python frame'
return
pyop = frame.get_pyop()
if not pyop:
print 'Unable to read information on python frame'
return
filename = pyop.filename()
lineno = pyop.current_line_num()
if start is None:
start = lineno - 5
end = lineno + 5
if start<1:
start = 1
with open(filename, 'r') as f:
all_lines = f.readlines()
# start and end are 1-based, all_lines is 0-based;
# so [start-1:end] as a python slice gives us [start, end] as a
# closed interval
for i, line in enumerate(all_lines[start-1:end]):
linestr = str(i+start)
# Highlight current line:
if i + start == lineno:
linestr = '>' + linestr
sys.stdout.write('%4s %s' % (linestr, line))
# ...and register the command:
PyList()
def move_in_stack(move_up):
'''Move up or down the stack (for the py-up/py-down command)'''
frame = Frame.get_selected_python_frame()
while frame:
if move_up:
iter_frame = frame.older()
else:
iter_frame = frame.newer()
if not iter_frame:
break
if iter_frame.is_evalframeex():
# Result:
if iter_frame.select():
iter_frame.print_summary()
return
frame = iter_frame
if move_up:
print 'Unable to find an older python frame'
else:
print 'Unable to find a newer python frame'
class PyUp(gdb.Command):
'Select and print the python stack frame that called this one (if any)'
def __init__(self):
gdb.Command.__init__ (self,
"py-up",
gdb.COMMAND_STACK,
gdb.COMPLETE_NONE)
def invoke(self, args, from_tty):
move_in_stack(move_up=True)
class PyDown(gdb.Command):
'Select and print the python stack frame called by this one (if any)'
def __init__(self):
gdb.Command.__init__ (self,
"py-down",
gdb.COMMAND_STACK,
gdb.COMPLETE_NONE)
def invoke(self, args, from_tty):
move_in_stack(move_up=False)
# Not all builds of gdb have gdb.Frame.select
if hasattr(gdb.Frame, 'select'):
PyUp()
PyDown()
class PyBacktrace(gdb.Command):
'Display the current python frame and all the frames within its call stack (if any)'
def __init__(self):
gdb.Command.__init__ (self,
"py-bt",
gdb.COMMAND_STACK,
gdb.COMPLETE_NONE)
def invoke(self, args, from_tty):
frame = Frame.get_selected_python_frame()
while frame:
if frame.is_evalframeex():
frame.print_summary()
frame = frame.older()
PyBacktrace()
class PyPrint(gdb.Command):
'Look up the given python variable name, and print it'
def __init__(self):
gdb.Command.__init__ (self,
"py-print",
gdb.COMMAND_DATA,
gdb.COMPLETE_NONE)
def invoke(self, args, from_tty):
name = str(args)
frame = Frame.get_selected_python_frame()
if not frame:
print 'Unable to locate python frame'
return
pyop_frame = frame.get_pyop()
if not pyop_frame:
print 'Unable to read information on python frame'
return
pyop_var, scope = pyop_frame.get_var_by_name(name)
if pyop_var:
print ('%s %r = %s'
% (scope,
name,
pyop_var.get_truncated_repr(MAX_OUTPUT_LEN)))
else:
print '%r not found' % name
PyPrint()
class PyLocals(gdb.Command):
'Look up the given python variable name, and print it'
def __init__(self):
gdb.Command.__init__ (self,
"py-locals",
gdb.COMMAND_DATA,
gdb.COMPLETE_NONE)
def invoke(self, args, from_tty):
name = str(args)
frame = Frame.get_selected_python_frame()
if not frame:
print 'Unable to locate python frame'
return
pyop_frame = frame.get_pyop()
if not pyop_frame:
print 'Unable to read information on python frame'
return
for pyop_name, pyop_value in pyop_frame.iter_locals():
print ('%s = %s'
% (pyop_name.proxyval(set()),
pyop_value.get_truncated_repr(MAX_OUTPUT_LEN)))
PyLocals() cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Debugging.py 0000664 0000000 0000000 00000001050 11446142532 0023451 0 ustar 00root root 0000000 0000000 ###############################################
#
# Odds and ends for debugging
#
###############################################
def print_call_chain(*args):
import sys
print(" ".join(map(str, args)))
f = sys._getframe(1)
while f:
name = f.f_code.co_name
s = f.f_locals.get('self', None)
if s:
c = getattr(s, "__class__", None)
if c:
name = "%s.%s" % (c.__name__, name)
print("Called from: %s %s" % (name, f.f_lineno))
f = f.f_back
print("-" * 70)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Distutils/ 0000775 0000000 0000000 00000000000 11446142532 0023174 5 ustar 00root root 0000000 0000000 cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Distutils/__init__.py 0000664 0000000 0000000 00000000575 11446142532 0025314 0 ustar 00root root 0000000 0000000 # July 2002, Graham Fawcett
#
# this hack was inspired by the way Thomas Heller got py2exe
# to appear as a distutil command
#
# we replace distutils.command.build_ext with our own version
# and keep the old one under the module name _build_ext,
# so that *our* build_ext can make use of it.
from Cython.Distutils.build_ext import build_ext
# from extension import Extension
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Distutils/build_ext.py 0000664 0000000 0000000 00000021604 11446142532 0025530 0 ustar 00root root 0000000 0000000 """Cython.Distutils.build_ext
Implements a version of the Distutils 'build_ext' command, for
building Cython extension modules."""
# This module should be kept compatible with Python 2.1.
__revision__ = "$Id:$"
import sys, os, re
from types import *
from distutils.core import Command
from distutils.errors import *
from distutils.sysconfig import customize_compiler, get_python_version
from distutils.dep_util import newer, newer_group
from distutils import log
from distutils.dir_util import mkpath
from distutils.command import build_ext as _build_ext
extension_name_re = _build_ext.extension_name_re
show_compilers = _build_ext.show_compilers
class build_ext(_build_ext.build_ext):
description = "build C/C++ and Cython extensions (compile/link to build directory)"
sep_by = _build_ext.build_ext.sep_by
user_options = _build_ext.build_ext.user_options
boolean_options = _build_ext.build_ext.boolean_options
help_options = _build_ext.build_ext.help_options
# Add the pyrex specific data.
user_options.extend([
('pyrex-cplus', None,
"generate C++ source files"),
('pyrex-create-listing', None,
"write errors to a listing file"),
('pyrex-line-directives', None,
"emit source line directives"),
('pyrex-include-dirs=', None,
"path to the Cython include files" + sep_by),
('pyrex-c-in-temp', None,
"put generated C files in temp directory"),
('pyrex-gen-pxi', None,
"generate .pxi file for public declarations"),
('pyrex-directives=', None,
"compiler directive overrides"),
('pyrex-debug', None,
"generate debug information for cygdb"),
])
boolean_options.extend([
'pyrex-cplus', 'pyrex-create-listing', 'pyrex-line-directives',
'pyrex-c-in-temp', 'pyrex-debug',
])
def initialize_options(self):
_build_ext.build_ext.initialize_options(self)
self.pyrex_cplus = 0
self.pyrex_create_listing = 0
self.pyrex_line_directives = 0
self.pyrex_include_dirs = None
self.pyrex_directives = None
self.pyrex_c_in_temp = 0
self.pyrex_gen_pxi = 0
self.pyrex_debug = False
def finalize_options (self):
_build_ext.build_ext.finalize_options(self)
if self.pyrex_include_dirs is None:
self.pyrex_include_dirs = []
elif type(self.pyrex_include_dirs) is StringType:
self.pyrex_include_dirs = \
self.pyrex_include_dirs.split(os.pathsep)
if self.pyrex_directives is None:
self.pyrex_directives = {}
# finalize_options ()
def build_extensions(self):
# First, sanity-check the 'extensions' list
self.check_extensions_list(self.extensions)
for ext in self.extensions:
ext.sources = self.cython_sources(ext.sources, ext)
self.build_extension(ext)
def cython_sources(self, sources, extension):
"""
Walk the list of source files in 'sources', looking for Cython
source files (.pyx and .py). Run Cython on all that are
found, and return a modified 'sources' list with Cython source
files replaced by the generated C (or C++) files.
"""
try:
from Cython.Compiler.Main \
import CompilationOptions, \
default_options as pyrex_default_options, \
compile as cython_compile
from Cython.Compiler.Errors import PyrexError
except ImportError:
e = sys.exc_info()[1]
print("failed to import Cython: %s" % e)
raise DistutilsPlatformError("Cython does not appear to be installed")
new_sources = []
pyrex_sources = []
pyrex_targets = {}
# Setup create_list and cplus from the extension options if
# Cython.Distutils.extension.Extension is used, otherwise just
# use what was parsed from the command-line or the configuration file.
# cplus will also be set to true is extension.language is equal to
# 'C++' or 'c++'.
#try:
# create_listing = self.pyrex_create_listing or \
# extension.pyrex_create_listing
# cplus = self.pyrex_cplus or \
# extension.pyrex_cplus or \
# (extension.language != None and \
# extension.language.lower() == 'c++')
#except AttributeError:
# create_listing = self.pyrex_create_listing
# cplus = self.pyrex_cplus or \
# (extension.language != None and \
# extension.language.lower() == 'c++')
create_listing = self.pyrex_create_listing or \
getattr(extension, 'pyrex_create_listing', 0)
line_directives = self.pyrex_line_directives or \
getattr(extension, 'pyrex_line_directives', 0)
cplus = self.pyrex_cplus or getattr(extension, 'pyrex_cplus', 0) or \
(extension.language and extension.language.lower() == 'c++')
pyrex_gen_pxi = self.pyrex_gen_pxi or getattr(extension, 'pyrex_gen_pxi', 0)
pyrex_debug = self.pyrex_debug or getattr(extension, 'pyrex_debug', False)
# Set up the include_path for the Cython compiler:
# 1. Start with the command line option.
# 2. Add in any (unique) paths from the extension
# pyrex_include_dirs (if Cython.Distutils.extension is used).
# 3. Add in any (unique) paths from the extension include_dirs
includes = self.pyrex_include_dirs
try:
for i in extension.pyrex_include_dirs:
if not i in includes:
includes.append(i)
except AttributeError:
pass
for i in extension.include_dirs:
if not i in includes:
includes.append(i)
# Set up Cython compiler directives:
# 1. Start with the command line option.
# 2. Add in any (unique) entries from the extension
# pyrex_directives (if Cython.Distutils.extension is used).
directives = self.pyrex_directives
if hasattr(extension, "pyrex_directives"):
directives.update(extension.pyrex_directives)
# Set the target_ext to '.c'. Cython will change this to '.cpp' if
# needed.
if cplus:
target_ext = '.cpp'
else:
target_ext = '.c'
# Decide whether to drop the generated C files into the temp dir
# or the source tree.
if not self.inplace and (self.pyrex_c_in_temp
or getattr(extension, 'pyrex_c_in_temp', 0)):
target_dir = os.path.join(self.build_temp, "pyrex")
else:
target_dir = None
newest_dependency = None
for source in sources:
(base, ext) = os.path.splitext(os.path.basename(source))
if ext == ".py":
# FIXME: we might want to special case this some more
ext = '.pyx'
if ext == ".pyx": # Cython source file
output_dir = target_dir or os.path.dirname(source)
new_sources.append(os.path.join(output_dir, base + target_ext))
pyrex_sources.append(source)
pyrex_targets[source] = new_sources[-1]
elif ext == '.pxi' or ext == '.pxd':
if newest_dependency is None \
or newer(source, newest_dependency):
newest_dependency = source
else:
new_sources.append(source)
if not pyrex_sources:
return new_sources
module_name = extension.name
for source in pyrex_sources:
target = pyrex_targets[source]
depends = [source] + list(extension.depends or ())
rebuild = self.force or newer_group(depends, target, 'newer')
if not rebuild and newest_dependency is not None:
rebuild = newer(newest_dependency, target)
if rebuild:
log.info("cythoning %s to %s", source, target)
self.mkpath(os.path.dirname(target))
options = CompilationOptions(pyrex_default_options,
use_listing_file = create_listing,
include_path = includes,
compiler_directives = directives,
output_file = target,
cplus = cplus,
emit_linenums = line_directives,
generate_pxi = pyrex_gen_pxi,
debug = pyrex_debug)
result = cython_compile(source, options=options,
full_module_name=module_name)
else:
log.info("skipping '%s' Cython extension (up-to-date)", target)
return new_sources
# cython_sources ()
# class build_ext
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Distutils/extension.py 0000664 0000000 0000000 00000006054 11446142532 0025567 0 ustar 00root root 0000000 0000000 """Pyrex.Distutils.extension
Provides a modified Extension class, that understands hou to describe
Pyrex extension modules in setup scripts."""
__revision__ = "$Id:$"
import os, sys
from types import *
import distutils.extension as _Extension
try:
import warnings
except ImportError:
warnings = None
class Extension(_Extension.Extension):
_Extension.Extension.__doc__ + \
"""pyrex_include_dirs : [string]
list of directories to search for Pyrex header files (.pxd) (in
Unix form for portability)
pyrex_directives : {string:value}
dict of compiler directives
pyrex_create_listing_file : boolean
write pyrex error messages to a listing (.lis) file.
pyrex_line_directivess : boolean
emit pyx line numbers for debugging/profiling
pyrex_cplus : boolean
use the C++ compiler for compiling and linking.
pyrex_c_in_temp : boolean
put generated C files in temp directory.
pyrex_gen_pxi : boolean
generate .pxi file for public declarations
pyrex_debug : boolean
generate Cython debug information for this extension for cygdb
"""
# When adding arguments to this constructor, be sure to update
# user_options.extend in build_ext.py.
def __init__ (self, name, sources,
include_dirs = None,
define_macros = None,
undef_macros = None,
library_dirs = None,
libraries = None,
runtime_library_dirs = None,
extra_objects = None,
extra_compile_args = None,
extra_link_args = None,
export_symbols = None,
#swig_opts = None,
depends = None,
language = None,
pyrex_include_dirs = None,
pyrex_directives = None,
pyrex_create_listing = 0,
pyrex_line_directives = 0,
pyrex_cplus = 0,
pyrex_c_in_temp = 0,
pyrex_gen_pxi = 0,
pyrex_debug = False,
**kw):
_Extension.Extension.__init__(self, name, sources,
include_dirs = include_dirs,
define_macros = define_macros,
undef_macros = undef_macros,
library_dirs = library_dirs,
libraries = libraries,
runtime_library_dirs = runtime_library_dirs,
extra_objects = extra_objects,
extra_compile_args = extra_compile_args,
extra_link_args = extra_link_args,
export_symbols = export_symbols,
#swig_opts = swig_opts,
depends = depends,
language = language,
**kw)
self.pyrex_include_dirs = pyrex_include_dirs or []
self.pyrex_directives = pyrex_directives or {}
self.pyrex_create_listing = pyrex_create_listing
self.pyrex_line_directives = pyrex_line_directives
self.pyrex_cplus = pyrex_cplus
self.pyrex_c_in_temp = pyrex_c_in_temp
self.pyrex_gen_pxi = pyrex_gen_pxi
self.pyrex_debug = pyrex_debug
# class Extension
read_setup_file = _Extension.read_setup_file
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/ 0000775 0000000 0000000 00000000000 11446142532 0022756 5 ustar 00root root 0000000 0000000 cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/ 0000775 0000000 0000000 00000000000 11446142532 0025016 5 ustar 00root root 0000000 0000000 cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python.pxd 0000664 0000000 0000000 00000000075 11446142532 0027056 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python2.5.pxd 0000664 0000000 0000000 00000115664 11446142532 0027316 0 ustar 00root root 0000000 0000000 # From: Eric Huss
#
# Here is my latest copy. It does not cover 100% of the API. It should be
# current up to 2.5.
#
# -Eric
# XXX:
# - Need to support "long long" definitions that are different for different platforms.
# - Support unicode platform dependencies.
# - Add unicode calls.
# - Add setobject calls.
cdef extern from "stdio.h":
ctypedef struct FILE:
pass
cdef extern from "Python.h":
# XXX: This is platform dependent.
ctypedef unsigned short Py_UNICODE
ctypedef struct PyTypeObject:
pass
ctypedef struct PyObject:
Py_ssize_t ob_refcnt
PyTypeObject * ob_type
###############################################################################################
# bool
###############################################################################################
PyObject * Py_False
PyObject * Py_True
PyTypeObject PyBool_Type
int PyBool_Check (object) # Always succeeds.
object PyBool_FromLong (long)
###############################################################################################
# buffer
###############################################################################################
PyTypeObject PyBuffer_Type
int Py_END_OF_BUFFER
int PyBuffer_Check (object) # Always succeeds.
object PyBuffer_FromMemory (void *, Py_ssize_t)
object PyBuffer_FromObject (object, Py_ssize_t, Py_ssize_t)
object PyBuffer_FromReadWriteMemory (void *, Py_ssize_t)
object PyBuffer_FromReadWriteObject (object, Py_ssize_t, Py_ssize_t)
object PyBuffer_New (Py_ssize_t)
int PyObject_AsCharBuffer (object, char **, Py_ssize_t *) except -1
int PyObject_AsReadBuffer (object, void **, Py_ssize_t *) except -1
int PyObject_AsWriteBuffer (object, void **, Py_ssize_t *) except -1
int PyObject_CheckReadBuffer (object) # Always succeeds.
###############################################################################################
# cobject
###############################################################################################
PyTypeObject PyCObject_Type
int PyCObject_Check(object) # Always succeeds.
object PyCObject_FromVoidPtr(void *, void (*)(void*))
object PyCObject_FromVoidPtrAndDesc(void *, void *, void (*)(void*,void*))
void * PyCObject_AsVoidPtr(object) except NULL
void * PyCObject_GetDesc(object) except NULL
void * PyCObject_Import(char *, char *) except NULL
###############################################################################################
# compile
###############################################################################################
ctypedef struct PyCodeObject:
int co_argcount
int co_nlocals
int co_stacksize
int co_flags
PyObject *co_code
PyObject *co_consts
PyObject *co_names
PyObject *co_varnames
PyObject *co_freevars
PyObject *co_cellvars
PyObject *co_filename
PyObject *co_name
int co_firstlineno
PyObject *co_lnotab
int PyCode_Addr2Line(PyCodeObject *, int)
###############################################################################################
# complex
###############################################################################################
ctypedef struct Py_complex:
double real
double imag
PyTypeObject PyComplex_Type
Py_complex PyComplex_AsCComplex (object) # Always succeeds.
int PyComplex_Check (object) # Always succeeds.
int PyComplex_CheckExact (object) # Always succeeds.
object PyComplex_FromCComplex (Py_complex)
object PyComplex_FromDoubles (double, double)
double PyComplex_ImagAsDouble (object) except? -1
double PyComplex_RealAsDouble (object) except? -1
Py_complex _Py_c_diff (Py_complex, Py_complex)
Py_complex _Py_c_neg (Py_complex)
Py_complex _Py_c_pow (Py_complex, Py_complex)
Py_complex _Py_c_prod (Py_complex, Py_complex)
Py_complex _Py_c_quot (Py_complex, Py_complex)
Py_complex _Py_c_sum (Py_complex, Py_complex)
###############################################################################################
# dict
###############################################################################################
PyTypeObject PyDict_Type
int PyDict_Check (object) # Always succeeds.
int PyDict_CheckExact (object) # Always succeeds.
void PyDict_Clear (object)
int PyDict_Contains (object, object) except -1
object PyDict_Copy (object)
int PyDict_DelItem (object, object) except -1
int PyDict_DelItemString (object, char *) except -1
object PyDict_Items (object)
object PyDict_Keys (object)
int PyDict_Merge (object, object, int) except -1
int PyDict_MergeFromSeq2 (object, object, int) except -1
object PyDict_New ()
# XXX: Pyrex doesn't support pointer to a python object?
#int PyDict_Next (object, Py_ssize_t *, object *, object *) # Always succeeds.
int PyDict_SetItem (object, object, object) except -1
int PyDict_SetItemString (object, char *, object) except -1
Py_ssize_t PyDict_Size (object) except -1
int PyDict_Update (object, object) except -1
object PyDict_Values (object)
# XXX: Borrowed reference. No exception on NULL.
#object PyDict_GetItem (object, object)
# XXX: Borrowed reference. No exception on NULL
#object PyDict_GetItemString (object, char *)
###############################################################################################
# float
###############################################################################################
PyTypeObject PyFloat_Type
int _PyFloat_Pack4 (double, unsigned char *, int) except -1
int _PyFloat_Pack8 (double, unsigned char *, int) except -1
double _PyFloat_Unpack4 (unsigned char *, int) except? -1
double _PyFloat_Unpack8 (unsigned char *, int) except? -1
double PyFloat_AS_DOUBLE (object)
double PyFloat_AsDouble (object) except? -1
void PyFloat_AsReprString (char*, object)
void PyFloat_AsString (char*, object)
int PyFloat_Check (object) # Always succeeds.
int PyFloat_CheckExact (object) # Always succeeds.
object PyFloat_FromDouble (double)
object PyFloat_FromString (object, char**)
###############################################################################################
# frame
###############################################################################################
ctypedef struct PyFrameObject:
PyFrameObject *f_back
PyCodeObject *f_code
PyObject *f_builtins
PyObject *f_globals
PyObject *f_locals
PyObject *f_trace
PyObject *f_exc_type
PyObject *f_exc_value
PyObject *f_exc_traceback
int f_lasti
int f_lineno
int f_restricted
int f_iblock
int f_nlocals
int f_ncells
int f_nfreevars
int f_stacksize
###############################################################################################
# int
###############################################################################################
PyTypeObject PyInt_Type
long PyInt_AS_LONG (object) # Always succeeds.
long PyInt_AsLong (object) except? -1
Py_ssize_t PyInt_AsSsize_t (object) except? -1
unsigned long long PyInt_AsUnsignedLongLongMask (object) except? -1
unsigned long PyInt_AsUnsignedLongMask (object) except? -1
int PyInt_Check (object) # Always succeeds.
int PyInt_CheckExact (object) # Always succeeds.
object PyInt_FromLong (long)
object PyInt_FromSsize_t (Py_ssize_t)
object PyInt_FromString (char*, char**, int)
object PyInt_FromUnicode (Py_UNICODE*, Py_ssize_t, int)
long PyInt_GetMax () # Always succeeds.
###############################################################################################
# iterator
###############################################################################################
int PyIter_Check (object) # Always succeeds.
object PyIter_Next (object)
###############################################################################################
# list
###############################################################################################
PyTypeObject PyList_Type
int PyList_Append (object, object) except -1
object PyList_AsTuple (object)
int PyList_Check (object) # Always succeeds.
int PyList_CheckExact (object) # Always succeeds.
int PyList_GET_SIZE (object) # Always suceeds.
object PyList_GetSlice (object, Py_ssize_t, Py_ssize_t)
int PyList_Insert (object, Py_ssize_t, object) except -1
object PyList_New (Py_ssize_t)
int PyList_Reverse (object) except -1
int PyList_SetSlice (object, Py_ssize_t, Py_ssize_t, object) except -1
Py_ssize_t PyList_Size (object) except -1
int PyList_Sort (object) except -1
###############################################################################################
# long
###############################################################################################
PyTypeObject PyLong_Type
int _PyLong_AsByteArray (object, unsigned char *, size_t, int, int) except -1
object _PyLong_FromByteArray (unsigned char *, size_t, int, int)
size_t _PyLong_NumBits (object) except -1
int _PyLong_Sign (object) # No error.
long PyLong_AsLong (object) except? -1
long long PyLong_AsLongLong (object) except? -1
unsigned long PyLong_AsUnsignedLong (object) except? -1
unsigned long PyLong_AsUnsignedLongMask (object) except? -1
unsigned long long PyLong_AsUnsignedLongLong (object) except? -1
unsigned long long PyLong_AsUnsignedLongLongMask (object) except? -1
int PyLong_Check (object) # Always succeeds.
int PyLong_CheckExact (object) # Always succeeds.
object PyLong_FromDouble (double)
object PyLong_FromLong (long)
object PyLong_FromLongLong (long long)
object PyLong_FromUnsignedLong (unsigned long)
object PyLong_FromUnsignedLongLong (unsigned long long)
double PyLong_AsDouble (object) except? -1
object PyLong_FromVoidPtr (void *)
void * PyLong_AsVoidPtr (object) except NULL
object PyLong_FromString (char *, char **, int)
object PyLong_FromUnicode (Py_UNICODE*, Py_ssize_t, int)
###############################################################################################
# mapping
###############################################################################################
int PyMapping_Check (object) # Always succeeds.
int PyMapping_DelItem (object, object) except -1
int PyMapping_DelItemString (object, char *) except -1
object PyMapping_GetItemString (object, char *)
int PyMapping_HasKey (object, object) # Always succeeds.
int PyMapping_HasKeyString (object, char *) # Always succeeds.
object PyMapping_Items (object)
object PyMapping_Keys (object)
Py_ssize_t PyMapping_Length (object) except -1
int PyMapping_SetItemString (object, char *, object) except -1
Py_ssize_t PyMapping_Size (object) except -1
object PyMapping_Values (object)
###############################################################################################
# mem
###############################################################################################
void PyMem_Free (void * p)
void * PyMem_Malloc (size_t n)
void * PyMem_Realloc (void *, size_t)
###############################################################################################
# modsupport
###############################################################################################
object Py_BuildValue (char *, ...)
object Py_VaBuildValue (char *, va_list)
###############################################################################################
# number
###############################################################################################
object PyNumber_Absolute (object)
object PyNumber_Add (object, object)
object PyNumber_And (object, object)
Py_ssize_t PyNumber_AsSsize_t (object, object) except? -1
int PyNumber_Check (object) # Always succeeds.
# XXX: Pyrex doesn't support pointer to python object?
#int PyNumber_Coerce (object*, object*) except -1
object PyNumber_Divide (object, object)
object PyNumber_Divmod (object, object)
object PyNumber_Float (object)
object PyNumber_FloorDivide (object, object)
object PyNumber_InPlaceAdd (object, object)
object PyNumber_InPlaceAnd (object, object)
object PyNumber_InPlaceDivide (object, object)
object PyNumber_InPlaceFloorDivide (object, object)
object PyNumber_InPlaceLshift (object, object)
object PyNumber_InPlaceMultiply (object, object)
object PyNumber_InPlaceOr (object, object)
object PyNumber_InPlacePower (object, object, object)
object PyNumber_InPlaceRemainder (object, object)
object PyNumber_InPlaceRshift (object, object)
object PyNumber_InPlaceSubtract (object, object)
object PyNumber_InPlaceTrueDivide (object, object)
object PyNumber_InPlaceXor (object, object)
object PyNumber_Int (object)
object PyNumber_Invert (object)
object PyNumber_Long (object)
object PyNumber_Lshift (object, object)
object PyNumber_Multiply (object, object)
object PyNumber_Negative (object)
object PyNumber_Or (object, object)
object PyNumber_Positive (object)
object PyNumber_Power (object, object, object)
object PyNumber_Remainder (object, object)
object PyNumber_Rshift (object, object)
object PyNumber_Subtract (object, object)
object PyNumber_TrueDivide (object, object)
object PyNumber_Xor (object, object)
###############################################################################################
# object
###############################################################################################
int PyCallable_Check (object) # Always succeeds.
int PyObject_AsFileDescriptor (object) except -1
object PyObject_Call (object, object, object)
object PyObject_CallFunction (object, char *, ...)
object PyObject_CallFunctionObjArgs (object, ...)
object PyObject_CallMethod (object, char *, char *, ...)
object PyObject_CallMethodObjArgs (object, object, ...)
object PyObject_CallObject (object, object)
int PyObject_Cmp (object, object, int *result) except -1
# Use PyObject_Cmp instead.
#int PyObject_Compare (object, object)
int PyObject_DelAttr (object, object) except -1
int PyObject_DelAttrString (object, char *) except -1
int PyObject_DelItem (object, object) except -1
int PyObject_DelItemString (object, char *) except -1
object PyObject_Dir (object)
object PyObject_GetAttr (object, object)
object PyObject_GetAttrString (object, char *)
object PyObject_GetItem (object, object)
object PyObject_GetIter (object)
int PyObject_HasAttr (object, object) # Always succeeds.
int PyObject_HasAttrString (object, char *) # Always succeeds.
long PyObject_Hash (object) except -1
int PyObject_IsInstance (object, object) except -1
int PyObject_IsSubclass (object, object) except -1
int PyObject_IsTrue (object) except -1
Py_ssize_t PyObject_Length (object) except -1
int PyObject_Not (object) except -1
int PyObject_Print (object, FILE *, int) except -1
object PyObject_Repr (object)
object PyObject_RichCompare (object, object, int)
int PyObject_RichCompareBool (object, object, int) except -1
int PyObject_SetAttr (object, object, object) except -1
int PyObject_SetAttrString (object, char *, object) except -1
int PyObject_SetItem (object, object, object) except -1
Py_ssize_t PyObject_Size (object) except -1
object PyObject_Str (object)
object PyObject_Type (object)
int PyObject_TypeCheck (object, object) # Always succeeds.
object PyObject_Unicode (object)
###############################################################################################
# pyerrors
###############################################################################################
int PyErr_BadArgument ()
void PyErr_BadInternalCall ()
int PyErr_CheckSignals ()
void PyErr_Clear ()
int PyErr_ExceptionMatches (object)
object PyErr_Format (object, char *, ...)
int PyErr_GivenExceptionMatches (object, object)
object PyErr_NoMemory ()
object PyErr_Occurred ()
void PyErr_Restore (object, object, object)
object PyErr_SetFromErrno (object)
object PyErr_SetFromErrnoWithFilename (object, char *)
object PyErr_SetFromErrnoWithFilenameObject (object, object)
void PyErr_SetInterrupt ()
void PyErr_SetNone (object)
void PyErr_SetObject (object, object)
void PyErr_SetString (object, char *)
int PyErr_Warn (object, char *)
int PyErr_WarnExplicit (object, char *, char *, int, char *, object)
void PyErr_WriteUnraisable (object)
###############################################################################################
# pyeval
# Be extremely careful with these functions.
###############################################################################################
ctypedef struct PyThreadState:
PyFrameObject * frame
int recursion_depth
void * curexc_type, * curexc_value, * curexc_traceback
void * exc_type, * exc_value, * exc_traceback
void PyEval_AcquireLock ()
void PyEval_ReleaseLock ()
void PyEval_AcquireThread (PyThreadState *)
void PyEval_ReleaseThread (PyThreadState *)
PyThreadState* PyEval_SaveThread ()
void PyEval_RestoreThread (PyThreadState *)
###############################################################################################
# pystate
# Be extremely careful with these functions. Read PEP 311 for more detail.
###############################################################################################
ctypedef int PyGILState_STATE
PyGILState_STATE PyGILState_Ensure ()
void PyGILState_Release (PyGILState_STATE)
ctypedef struct PyInterpreterState:
pass
PyThreadState* PyThreadState_New (PyInterpreterState *)
void PyThreadState_Clear (PyThreadState *)
void PyThreadState_Delete (PyThreadState *)
PyThreadState* PyThreadState_Get ()
PyThreadState* PyThreadState_Swap (PyThreadState *tstate)
# XXX: Borrowed reference.
#object PyThreadState_GetDict ()
###############################################################################################
# run
# Functions for embedded interpreters are not included.
###############################################################################################
ctypedef struct PyCompilerFlags:
int cf_flags
ctypedef struct _node:
pass
ctypedef void (*PyOS_sighandler_t)(int)
void PyErr_Display (object, object, object)
void PyErr_Print ()
void PyErr_PrintEx (int)
char * PyOS_Readline (FILE *, FILE *, char *)
PyOS_sighandler_t PyOS_getsig (int)
PyOS_sighandler_t PyOS_setsig (int, PyOS_sighandler_t)
_node * PyParser_SimpleParseFile (FILE *, char *, int) except NULL
_node * PyParser_SimpleParseFileFlags (FILE *, char *, int,
int) except NULL
_node * PyParser_SimpleParseString (char *, int) except NULL
_node * PyParser_SimpleParseStringFlagsFilename(char *, char *,
int, int) except NULL
_node * PyParser_SimpleParseStringFlags (char *, int, int) except NULL
int PyRun_AnyFile (FILE *, char *) except -1
int PyRun_AnyFileEx (FILE *, char *, int) except -1
int PyRun_AnyFileExFlags (FILE *, char *, int,
PyCompilerFlags *) except -1
int PyRun_AnyFileFlags (FILE *, char *,
PyCompilerFlags *) except -1
object PyRun_File (FILE *, char *, int,
object, object)
object PyRun_FileEx (FILE *, char *, int,
object, object, int)
object PyRun_FileExFlags (FILE *, char *, int,
object, object, int,
PyCompilerFlags *)
object PyRun_FileFlags (FILE *, char *, int,
object, object,
PyCompilerFlags *)
int PyRun_InteractiveLoop (FILE *, char *) except -1
int PyRun_InteractiveLoopFlags (FILE *, char *,
PyCompilerFlags *) except -1
int PyRun_InteractiveOne (FILE *, char *) except -1
int PyRun_InteractiveOneFlags (FILE *, char *,
PyCompilerFlags *) except -1
int PyRun_SimpleFile (FILE *, char *) except -1
int PyRun_SimpleFileEx (FILE *, char *, int) except -1
int PyRun_SimpleFileExFlags (FILE *, char *, int,
PyCompilerFlags *) except -1
int PyRun_SimpleString (char *) except -1
int PyRun_SimpleStringFlags (char *, PyCompilerFlags *) except -1
object PyRun_String (char *, int, object,
object)
object PyRun_StringFlags (char *, int, object,
object, PyCompilerFlags *)
int Py_AtExit (void (*func)())
object Py_CompileString (char *, char *, int)
object Py_CompileStringFlags (char *, char *, int, PyCompilerFlags *)
void Py_Exit (int)
int Py_FdIsInteractive (FILE *, char *) # Always succeeds.
char * Py_GetBuildInfo ()
char * Py_GetCompiler ()
char * Py_GetCopyright ()
char * Py_GetExecPrefix ()
char * Py_GetPath ()
char * Py_GetPlatform ()
char * Py_GetPrefix ()
char * Py_GetProgramFullPath ()
char * Py_GetProgramName ()
char * Py_GetPythonHome ()
char * Py_GetVersion ()
###############################################################################################
# sequence
###############################################################################################
int PySequence_Check (object) # Always succeeds.
object PySequence_Concat (object, object)
int PySequence_Contains (object, object) except -1
Py_ssize_t PySequence_Count (object, object) except -1
int PySequence_DelItem (object, Py_ssize_t) except -1
int PySequence_DelSlice (object, Py_ssize_t, Py_ssize_t) except -1
object PySequence_Fast (object, char *)
int PySequence_Fast_GET_SIZE (object)
object PySequence_GetItem (object, Py_ssize_t)
object PySequence_GetSlice (object, Py_ssize_t, Py_ssize_t)
object PySequence_ITEM (object, int)
int PySequence_In (object, object) except -1
object PySequence_InPlaceConcat (object, object)
object PySequence_InPlaceRepeat (object, Py_ssize_t)
Py_ssize_t PySequence_Index (object, object) except -1
Py_ssize_t PySequence_Length (object) except -1
object PySequence_List (object)
object PySequence_Repeat (object, Py_ssize_t)
int PySequence_SetItem (object, Py_ssize_t, object) except -1
int PySequence_SetSlice (object, Py_ssize_t, Py_ssize_t, object) except -1
Py_ssize_t PySequence_Size (object) except -1
object PySequence_Tuple (object)
###############################################################################################
# string
###############################################################################################
PyTypeObject PyString_Type
# Pyrex cannot support resizing because you have no choice but to use
# realloc which may call free() on the object, and there's no way to tell
# Pyrex to "forget" reference counting for the object.
#int _PyString_Resize (object *, Py_ssize_t) except -1
char * PyString_AS_STRING (object) # Always succeeds.
object PyString_AsDecodedObject (object, char *, char *)
object PyString_AsEncodedObject (object, char *, char *)
object PyString_AsEncodedString (object, char *, char *)
char * PyString_AsString (object) except NULL
int PyString_AsStringAndSize (object, char **, Py_ssize_t *) except -1
int PyString_Check (object) # Always succeeds.
int PyString_CHECK_INTERNED (object) # Always succeeds.
int PyString_CheckExact (object) # Always succeeds.
# XXX: Pyrex doesn't support pointer to a python object?
#void PyString_Concat (object *, object)
# XXX: Pyrex doesn't support pointer to a python object?
#void PyString_ConcatAndDel (object *, object)
object PyString_Decode (char *, int, char *, char *)
object PyString_DecodeEscape (char *, int, char *, int, char *)
object PyString_Encode (char *, int, char *, char *)
object PyString_Format (object, object)
object PyString_FromFormat (char*, ...)
object PyString_FromFormatV (char*, va_list)
object PyString_FromString (char *)
object PyString_FromStringAndSize (char *, Py_ssize_t)
Py_ssize_t PyString_GET_SIZE (object) # Always succeeds.
object PyString_InternFromString (char *)
# XXX: Pyrex doesn't support pointer to a python object?
#void PyString_InternImmortal (object*)
# XXX: Pyrex doesn't support pointer to a python object?
#void PyString_InternInPlace (object*)
object PyString_Repr (object, int)
Py_ssize_t PyString_Size (object) except -1
# Disgusting hack to access internal object values.
ctypedef struct PyStringObject:
int ob_refcnt
PyTypeObject * ob_type
int ob_size
long ob_shash
int ob_sstate
char * ob_sval
###############################################################################################
# tuple
###############################################################################################
PyTypeObject PyTuple_Type
# See PyString_Resize note about resizing.
#int _PyTuple_Resize (object*, Py_ssize_t) except -1
int PyTuple_Check (object) # Always succeeds.
int PyTuple_CheckExact (object) # Always succeeds.
Py_ssize_t PyTuple_GET_SIZE (object) # Always succeeds.
object PyTuple_GetSlice (object, Py_ssize_t, Py_ssize_t)
object PyTuple_New (Py_ssize_t)
object PyTuple_Pack (Py_ssize_t, ...)
Py_ssize_t PyTuple_Size (object) except -1
###############################################################################################
# Dangerous things!
# Do not use these unless you really, really know what you are doing.
###############################################################################################
void Py_INCREF (object)
void Py_XINCREF (object)
void Py_DECREF (object)
void Py_XDECREF (object)
void Py_CLEAR (object)
# XXX: Stolen reference.
void PyTuple_SET_ITEM (object, Py_ssize_t, value)
# XXX: Borrowed reference.
object PyTuple_GET_ITEM (object, Py_ssize_t)
# XXX: Borrowed reference.
object PyTuple_GetItem (object, Py_ssize_t)
# XXX: Stolen reference.
int PyTuple_SetItem (object, Py_ssize_t, object) except -1
# XXX: Steals reference.
int PyList_SetItem (object, Py_ssize_t, object) except -1
# XXX: Borrowed reference
object PyList_GetItem (object, Py_ssize_t)
# XXX: Borrowed reference, no NULL on error.
object PyList_GET_ITEM (object, Py_ssize_t)
# XXX: Stolen reference.
void PyList_SET_ITEM (object, Py_ssize_t, object)
# XXX: Borrowed reference.
object PySequence_Fast_GET_ITEM (object, Py_ssize_t)
# First parameter _must_ be a PyStringObject.
object _PyString_Join (object, object)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_bool.pxd 0000664 0000000 0000000 00000000102 11446142532 0030060 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.bool cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_buffer.pxd 0000664 0000000 0000000 00000000104 11446142532 0030400 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.buffer cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_bytes.pxd 0000664 0000000 0000000 00000000103 11446142532 0030254 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.bytes cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_cobject.pxd 0000664 0000000 0000000 00000000105 11446142532 0030541 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.cobject cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_complex.pxd 0000664 0000000 0000000 00000000105 11446142532 0030577 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.complex cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_dict.pxd 0000664 0000000 0000000 00000000102 11446142532 0030050 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.dict cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_exc.pxd 0000664 0000000 0000000 00000000101 11446142532 0027703 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.exc cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_float.pxd 0000664 0000000 0000000 00000000103 11446142532 0030233 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.float cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_function.pxd 0000664 0000000 0000000 00000000106 11446142532 0030756 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.function cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_getargs.pxd 0000664 0000000 0000000 00000000105 11446142532 0030564 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.getargs cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_instance.pxd 0000664 0000000 0000000 00000000106 11446142532 0030735 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.instance cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_int.pxd 0000664 0000000 0000000 00000000101 11446142532 0027716 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.int cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_iterator.pxd 0000664 0000000 0000000 00000000106 11446142532 0030762 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.iterator cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_list.pxd 0000664 0000000 0000000 00000000102 11446142532 0030100 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.list cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_long.pxd 0000664 0000000 0000000 00000000102 11446142532 0030064 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.long cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_mapping.pxd 0000664 0000000 0000000 00000000105 11446142532 0030563 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.mapping cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_mem.pxd 0000664 0000000 0000000 00000000101 11446142532 0027702 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.mem cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_method.pxd 0000664 0000000 0000000 00000000104 11446142532 0030407 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.method cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_module.pxd 0000664 0000000 0000000 00000000104 11446142532 0030414 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.module cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_number.pxd 0000664 0000000 0000000 00000000104 11446142532 0030417 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.number cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_object.pxd 0000664 0000000 0000000 00000000104 11446142532 0030375 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.object cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_oldbuffer.pxd 0000664 0000000 0000000 00000000107 11446142532 0031102 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.oldbuffer cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_pycapsule.pxd 0000664 0000000 0000000 00000000107 11446142532 0031137 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.pycapsule cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_ref.pxd 0000664 0000000 0000000 00000000101 11446142532 0027700 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.ref cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_sequence.pxd 0000664 0000000 0000000 00000000106 11446142532 0030741 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.sequence cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_set.pxd 0000664 0000000 0000000 00000000101 11446142532 0027717 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.set cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_string.pxd 0000664 0000000 0000000 00000000104 11446142532 0030435 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.string cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_tuple.pxd 0000664 0000000 0000000 00000000103 11446142532 0030257 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.tuple cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_type.pxd 0000664 0000000 0000000 00000000102 11446142532 0030106 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.type cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_unicode.pxd 0000664 0000000 0000000 00000000105 11446142532 0030556 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.unicode cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_version.pxd 0000664 0000000 0000000 00000000105 11446142532 0030615 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.version cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/python_weakref.pxd 0000664 0000000 0000000 00000000105 11446142532 0030554 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from cpython.weakref cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/stdio.pxd 0000664 0000000 0000000 00000000100 11446142532 0026644 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from libc.stdio cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/stdlib.pxd 0000664 0000000 0000000 00000000101 11446142532 0027004 0 ustar 00root root 0000000 0000000 # Present for backwards compatability
from libc.stdlib cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/Deprecated/stl.pxd 0000664 0000000 0000000 00000004346 11446142532 0026344 0 ustar 00root root 0000000 0000000 cdef extern from "" namespace std:
cdef cppclass vector[TYPE]:
#constructors
__init__()
__init__(vector&)
__init__(int)
__init__(int, TYPE&)
__init__(iterator, iterator)
#operators
TYPE& __getitem__(int)
TYPE& __setitem__(int, TYPE&)
vector __new__(vector&)
bool __eq__(vector&, vector&)
bool __ne__(vector&, vector&)
bool __lt__(vector&, vector&)
bool __gt__(vector&, vector&)
bool __le__(vector&, vector&)
bool __ge__(vector&, vector&)
#others
void assign(int, TYPE)
#void assign(iterator, iterator)
TYPE& at(int)
TYPE& back()
iterator begin()
int capacity()
void clear()
bool empty()
iterator end()
iterator erase(iterator)
iterator erase(iterator, iterator)
TYPE& front()
iterator insert(iterator, TYPE&)
void insert(iterator, int, TYPE&)
void insert(iterator, iterator)
int max_size()
void pop_back()
void push_back(TYPE&)
iterator rbegin()
iterator rend()
void reserve(int)
void resize(int)
void resize(int, TYPE&) #void resize(size_type num, const TYPE& = TYPE())
int size()
void swap(container&)
cdef extern from "" namespace std:
cdef cppclass deque[TYPE]:
#constructors
__init__()
__init__(deque&)
__init__(int)
__init__(int, TYPE&)
__init__(iterator, iterator)
#operators
TYPE& operator[]( size_type index );
const TYPE& operator[]( size_type index ) const;
deque __new__(deque&);
bool __eq__(deque&, deque&);
bool __ne__(deque&, deque&);
bool __lt__(deque&, deque&);
bool __gt__(deque&, deque&);
bool __le__(deque&, deque&);
bool __ge__(deque&, deque&);
#others
void assign(int, TYPE&)
void assign(iterator, iterator)
TYPE& at(int)
TYPE& back()
iterator begin()
void clear()
bool empty()
iterator end()
iterator erase(iterator)
iterator erase(iterator, iterator)
TYPE& front()
iterator insert(iterator, TYPE&)
void insert(iterator, int, TYPE&)
void insert(iterator, iterator, iterator)
int max_size()
void pop_back()
void pop_front()
void push_back(TYPE&)
void push_front(TYPE&)
iterator rbegin()
iterator rend()
void resize(int)
void resize(int, TYPE&)
int size()
void swap(container&)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/ 0000775 0000000 0000000 00000000000 11446142532 0024442 5 ustar 00root root 0000000 0000000 cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/__init__.pxd 0000664 0000000 0000000 00000016210 11446142532 0026716 0 ustar 00root root 0000000 0000000 #####################################################################
#
# These are the Cython pxd files for (most of) the Python/C API.
#
# REFERENCE COUNTING:
#
# JUST TO SCARE YOU:
# If you are going to use any of the Python/C API in your Cython
# program, you might be responsible for doing reference counting.
# Read http://docs.python.org/api/refcounts.html which is so
# important I've copied it below.
#
# For all the declaration below, whenver the Py_ function returns
# a *new reference* to a PyObject*, the return type is "object".
# When the function returns a borrowed reference, the return
# type is PyObject*. When Cython sees "object" as a return type
# it doesn't increment the reference count. When it sees PyObject*
# in order to use the result you must explicitly cast to ,
# and when you do that Cython increments the reference count wether
# you want it to or not, forcing you to an explicit DECREF (or leak memory).
# To avoid this we make the above convention. Note, you can
# always locally override this convention by putting something like
#
# cdef extern from "Python.h":
# PyObject* PyNumber_Add(PyObject *o1, PyObject *o2)
#
# in your file after any .pxi includes. Cython will use the latest
# declaration.
#
# Cython takes care of this automatically for anything of type object.
## More precisely, I think the correct convention for
## using the Python/C API from Pyrex is as follows.
##
## (1) Declare all input arguments as type "object". This way no explicit
## casting is needed, and moreover Pyrex doesn't generate
## any funny reference counting.
## (2) Declare output as object if a new reference is returned.
## (3) Declare output as PyObject* if a borrowed reference is returned.
##
## This way when you call objects, no cast is needed, and if the api
## calls returns a new reference (which is about 95% of them), then
## you can just assign to a variable of type object. With borrowed
## references if you do an explicit typecast to , Pyrex generates an
## INCREF and DECREF so you have to be careful. However, you got a
## borrowed reference in this case, so there's got to be another reference
## to your object, so you're OK, as long as you relealize this
## and use the result of an explicit cast to as a borrowed
## reference (and you can call Py_INCREF if you want to turn it
## into another reference for some reason).
#
# "The reference count is important because today's computers have
# a finite (and often severely limited) memory size; it counts how
# many different places there are that have a reference to an
# object. Such a place could be another object, or a global (or
# static) C variable, or a local variable in some C function. When
# an object's reference count becomes zero, the object is
# deallocated. If it contains references to other objects, their
# reference count is decremented. Those other objects may be
# deallocated in turn, if this decrement makes their reference
# count become zero, and so on. (There's an obvious problem with
# objects that reference each other here; for now, the solution is
# ``don't do that.'')
#
# Reference counts are always manipulated explicitly. The normal
# way is to use the macro Py_INCREF() to increment an object's
# reference count by one, and Py_DECREF() to decrement it by
# one. The Py_DECREF() macro is considerably more complex than the
# incref one, since it must check whether the reference count
# becomes zero and then cause the object's deallocator to be
# called. The deallocator is a function pointer contained in the
# object's type structure. The type-specific deallocator takes
# care of decrementing the reference counts for other objects
# contained in the object if this is a compound object type, such
# as a list, as well as performing any additional finalization
# that's needed. There's no chance that the reference count can
# overflow; at least as many bits are used to hold the reference
# count as there are distinct memory locations in virtual memory
# (assuming sizeof(long) >= sizeof(char*)). Thus, the reference
# count increment is a simple operation.
#
# It is not necessary to increment an object's reference count for
# every local variable that contains a pointer to an object. In
# theory, the object's reference count goes up by one when the
# variable is made to point to it and it goes down by one when the
# variable goes out of scope. However, these two cancel each other
# out, so at the end the reference count hasn't changed. The only
# real reason to use the reference count is to prevent the object
# from being deallocated as long as our variable is pointing to
# it. If we know that there is at least one other reference to the
# object that lives at least as long as our variable, there is no
# need to increment the reference count temporarily. An important
# situation where this arises is in objects that are passed as
# arguments to C functions in an extension module that are called
# from Python; the call mechanism guarantees to hold a reference
# to every argument for the duration of the call.
#
# However, a common pitfall is to extract an object from a list
# and hold on to it for a while without incrementing its reference
# count. Some other operation might conceivably remove the object
# from the list, decrementing its reference count and possible
# deallocating it. The real danger is that innocent-looking
# operations may invoke arbitrary Python code which could do this;
# there is a code path which allows control to flow back to the
# user from a Py_DECREF(), so almost any operation is potentially
# dangerous.
#
# A safe approach is to always use the generic operations
# (functions whose name begins with "PyObject_", "PyNumber_",
# "PySequence_" or "PyMapping_"). These operations always
# increment the reference count of the object they return. This
# leaves the caller with the responsibility to call Py_DECREF()
# when they are done with the result; this soon becomes second
# nature.
#
# Now you should read http://docs.python.org/api/refcountDetails.html
# just to be sure you understand what is going on.
#
#################################################################
from cpython.version cimport *
from cpython.ref cimport *
from cpython.exc cimport *
from cpython.module cimport *
from cpython.mem cimport *
from cpython.tuple cimport *
from cpython.list cimport *
from cpython.object cimport *
from cpython.sequence cimport *
from cpython.mapping cimport *
from cpython.iterator cimport *
from cpython.type cimport *
from cpython.number cimport *
from cpython.int cimport *
from cpython.bool cimport *
from cpython.long cimport *
from cpython.float cimport *
from cpython.complex cimport *
from cpython.string cimport *
from cpython.unicode cimport *
from cpython.dict cimport *
from cpython.instance cimport *
from cpython.function cimport *
from cpython.method cimport *
from cpython.weakref cimport *
from cpython.getargs cimport *
from cpython.pythread cimport *
# Python <= 2.x
from cpython.cobject cimport *
from cpython.oldbuffer cimport *
# Python >= 2.4
from cpython.set cimport *
# Python >= 2.6
from cpython.buffer cimport *
from cpython.bytes cimport *
# Python >= 3.0
from cpython.pycapsule cimport *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/bool.pxd 0000664 0000000 0000000 00000002522 11446142532 0026113 0 ustar 00root root 0000000 0000000
cdef extern from "Python.h":
############################################################################
# 7.2.2 Boolean Objects
############################################################################
ctypedef class __builtin__.bool [object PyBoolObject]:
pass
# Booleans in Python are implemented as a subclass of
# integers. There are only two booleans, Py_False and Py_True. As
# such, the normal creation and deletion functions don't apply to
# booleans. The following macros are available, however.
bint PyBool_Check(object o)
# Return true if o is of type PyBool_Type.
#PyObject* Py_False
# The Python False object. This object has no methods. It needs to
# be treated just like any other object with respect to reference
# counts.
#PyObject* Py_True
# The Python True object. This object has no methods. It needs to
# be treated just like any other object with respect to reference
# counts.
# Py_RETURN_FALSE
# Return Py_False from a function, properly incrementing its reference count.
# Py_RETURN_TRUE
# Return Py_True from a function, properly incrementing its reference count.
object PyBool_FromLong(long v)
# Return value: New reference.
# Return a new reference to Py_True or Py_False depending on the truth value of v.
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/buffer.pxd 0000664 0000000 0000000 00000011230 11446142532 0026425 0 ustar 00root root 0000000 0000000 # Please see the Python header files (object.h/abstract.h) for docs
cdef extern from "Python.h":
cdef enum:
PyBUF_SIMPLE,
PyBUF_WRITABLE,
PyBUF_WRITEABLE, # backwards compatability
PyBUF_FORMAT,
PyBUF_ND,
PyBUF_STRIDES,
PyBUF_C_CONTIGUOUS,
PyBUF_F_CONTIGUOUS,
PyBUF_ANY_CONTIGUOUS,
PyBUF_INDIRECT,
PyBUF_CONTIG,
PyBUF_CONTIG_RO,
PyBUF_STRIDED,
PyBUF_STRIDED_RO,
PyBUF_RECORDS,
PyBUF_RECORDS_RO,
PyBUF_FULL,
PyBUF_FULL_RO,
PyBUF_READ,
PyBUF_WRITE,
PyBUF_SHADOW
bint PyObject_CheckBuffer(object obj)
# Return 1 if obj supports the buffer interface otherwise 0.
int PyObject_GetBuffer(object obj, Py_buffer *view, int flags) except -1
# Export obj into a Py_buffer, view. These arguments must never be
# NULL. The flags argument is a bit field indicating what kind of
# buffer the caller is prepared to deal with and therefore what
# kind of buffer the exporter is allowed to return. The buffer
# interface allows for complicated memory sharing possibilities,
# but some caller may not be able to handle all the complexity but
# may want to see if the exporter will let them take a simpler
# view to its memory.
# Some exporters may not be able to share memory in every possible
# way and may need to raise errors to signal to some consumers
# that something is just not possible. These errors should be a
# BufferError unless there is another error that is actually
# causing the problem. The exporter can use flags information to
# simplify how much of the Py_buffer structure is filled in with
# non-default values and/or raise an error if the object can’t
# support a simpler view of its memory.
# 0 is returned on success and -1 on error.
void PyBuffer_Release(object obj, object view)
# Release the buffer view over obj. This should be called when the
# buffer is no longer being used as it may free memory from it.
void* PyBuffer_GetPointer(Py_buffer *view, Py_ssize_t *indices)
# ??
int PyBuffer_SizeFromFormat(char *) # actually const char
# Return the implied ~Py_buffer.itemsize from the struct-stype
# ~Py_buffer.format
int PyBuffer_ToContiguous(void *buf, Py_buffer *view, Py_ssize_t len, char fort)
# ??
int PyBuffer_FromContiguous(Py_buffer *view, void *buf, Py_ssize_t len, char fort)
# ??
int PyObject_CopyToObject(object obj, void *buf, Py_ssize_t len, char fortran) except -1
# Copy len bytes of data pointed to by the contiguous chunk of
# memory pointed to by buf into the buffer exported by obj. The
# buffer must of course be writable. Return 0 on success and
# return -1 and raise an error on failure. If the object does not
# have a writable buffer, then an error is raised. If fortran is
# 'F', then if the object is multi-dimensional, then the data will
# be copied into the array in Fortran-style (first dimension
# varies the fastest). If fortran is 'C', then the data will be
# copied into the array in C-style (last dimension varies the
# fastest). If fortran is 'A', then it does not matter and the
# copy will be made in whatever way is more efficient.
int PyObject_CopyData(object dest, object src) except -1
# Copy the data from the src buffer to the buffer of destination
bint PyBuffer_IsContiguous(Py_buffer *view, char fort)
# Return 1 if the memory defined by the view is C-style (fortran
# is 'C') or Fortran-style (fortran is 'F') contiguous or either
# one (fortran is 'A'). Return 0 otherwise.
void PyBuffer_FillContiguousStrides(int ndims,
Py_ssize_t *shape,
Py_ssize_t *strides,
int itemsize,
char fort)
# Fill the strides array with byte-strides of a contiguous
# (Fortran-style if fort is 'F' or C-style otherwise) array of the
# given shape with the given number of bytes per element.
int PyBuffer_FillInfo(Py_buffer *view, void *buf,
Py_ssize_t len, int readonly,
int flags) except -1
# Fill in a buffer-info structure, view, correctly for an exporter
# that can only share a contiguous chunk of memory of “unsigned
# bytes” of the given length. Return 0 on success and -1 (with
# raising an error) on error.
object PyObject_Format(object obj, object format_spec)
# Takes an arbitrary object and returns the result of calling
# obj.__format__(format_spec).
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/bytes.pxd 0000664 0000000 0000000 00000023301 11446142532 0026304 0 ustar 00root root 0000000 0000000 from cpython.ref cimport PyObject
cdef extern from "Python.h":
ctypedef struct va_list
############################################################################
# 7.3.1 String Objects
############################################################################
# These functions raise TypeError when expecting a string
# parameter and are called with a non-string parameter.
# PyStringObject
# This subtype of PyObject represents a Python bytes object.
# PyTypeObject PyBytes_Type
# This instance of PyTypeObject represents the Python bytes type;
# it is the same object as bytes and types.BytesType in the Python
# layer.
bint PyBytes_Check(object o)
# Return true if the object o is a string object or an instance of
# a subtype of the string type.
bint PyBytes_CheckExact(object o)
# Return true if the object o is a string object, but not an instance of a subtype of the string type.
bytes PyBytes_FromString(char *v)
# Return value: New reference.
# Return a new string object with the value v on success, and NULL
# on failure. The parameter v must not be NULL; it will not be
# checked.
bytes PyBytes_FromStringAndSize(char *v, Py_ssize_t len)
# Return value: New reference.
# Return a new string object with the value v and length len on
# success, and NULL on failure. If v is NULL, the contents of the
# string are uninitialized.
bytes PyBytes_FromFormat(char *format, ...)
# Return value: New reference.
# Take a C printf()-style format string and a variable number of
# arguments, calculate the size of the resulting Python string and
# return a string with the values formatted into it. The variable
# arguments must be C types and must correspond exactly to the
# format characters in the format string. The following format
# characters are allowed:
# Format Characters Type Comment
# %% n/a The literal % character.
# %c int A single character, represented as an C int.
# %d int Exactly equivalent to printf("%d").
# %u unsigned int Exactly equivalent to printf("%u").
# %ld long Exactly equivalent to printf("%ld").
# %lu unsigned long Exactly equivalent to printf("%lu").
# %zd Py_ssize_t Exactly equivalent to printf("%zd").
# %zu size_t Exactly equivalent to printf("%zu").
# %i int Exactly equivalent to printf("%i").
# %x int Exactly equivalent to printf("%x").
# %s char* A null-terminated C character array.
# %p void* The hex representation of a C pointer.
# Mostly equivalent to printf("%p") except that it is guaranteed to
# start with the literal 0x regardless of what the platform's printf
# yields.
# An unrecognized format character causes all the rest of the
# format string to be copied as-is to the result string, and any
# extra arguments discarded.
bytes PyBytes_FromFormatV(char *format, va_list vargs)
# Return value: New reference.
# Identical to PyBytes_FromFormat() except that it takes exactly two arguments.
Py_ssize_t PyBytes_Size(object string) except -1
# Return the length of the string in string object string.
Py_ssize_t PyBytes_GET_SIZE(object string)
# Macro form of PyBytes_Size() but without error checking.
char* PyBytes_AsString(object string) except NULL
# Return a NUL-terminated representation of the contents of
# string. The pointer refers to the internal buffer of string, not
# a copy. The data must not be modified in any way, unless the
# string was just created using PyBytes_FromStringAndSize(NULL,
# size). It must not be deallocated. If string is a Unicode
# object, this function computes the default encoding of string
# and operates on that. If string is not a string object at all,
# PyBytes_AsString() returns NULL and raises TypeError.
char* PyBytes_AS_STRING(object string)
# Macro form of PyBytes_AsString() but without error
# checking. Only string objects are supported; no Unicode objects
# should be passed.
int PyBytes_AsStringAndSize(object obj, char **buffer, Py_ssize_t *length) except -1
# Return a NULL-terminated representation of the contents of the
# object obj through the output variables buffer and length.
#
# The function accepts both string and Unicode objects as
# input. For Unicode objects it returns the default encoded
# version of the object. If length is NULL, the resulting buffer
# may not contain NUL characters; if it does, the function returns
# -1 and a TypeError is raised.
# The buffer refers to an internal string buffer of obj, not a
# copy. The data must not be modified in any way, unless the
# string was just created using PyBytes_FromStringAndSize(NULL,
# size). It must not be deallocated. If string is a Unicode
# object, this function computes the default encoding of string
# and operates on that. If string is not a string object at all,
# PyBytes_AsStringAndSize() returns -1 and raises TypeError.
void PyBytes_Concat(PyObject **string, object newpart)
# Create a new string object in *string containing the contents of
# newpart appended to string; the caller will own the new
# reference. The reference to the old value of string will be
# stolen. If the new string cannot be created, the old reference
# to string will still be discarded and the value of *string will
# be set to NULL; the appropriate exception will be set.
void PyBytes_ConcatAndDel(PyObject **string, object newpart)
# Create a new string object in *string containing the contents of
# newpart appended to string. This version decrements the
# reference count of newpart.
int _PyBytes_Resize(PyObject **string, Py_ssize_t newsize) except -1
# A way to resize a string object even though it is
# ``immutable''. Only use this to build up a brand new string
# object; don't use this if the string may already be known in
# other parts of the code. It is an error to call this function if
# the refcount on the input string object is not one. Pass the
# address of an existing string object as an lvalue (it may be
# written into), and the new size desired. On success, *string
# holds the resized string object and 0 is returned; the address
# in *string may differ from its input value. If the reallocation
# fails, the original string object at *string is deallocated,
# *string is set to NULL, a memory exception is set, and -1 is
# returned.
bytes PyBytes_Format(object format, object args)
# Return value: New reference. Return a new string object from
# format and args. Analogous to format % args. The args argument
# must be a tuple.
void PyBytes_InternInPlace(PyObject **string)
# Intern the argument *string in place. The argument must be the
# address of a pointer variable pointing to a Python string
# object. If there is an existing interned string that is the same
# as *string, it sets *string to it (decrementing the reference
# count of the old string object and incrementing the reference
# count of the interned string object), otherwise it leaves
# *string alone and interns it (incrementing its reference
# count). (Clarification: even though there is a lot of talk about
# reference counts, think of this function as
# reference-count-neutral; you own the object after the call if
# and only if you owned it before the call.)
bytes PyBytes_InternFromString(char *v)
# Return value: New reference.
# A combination of PyBytes_FromString() and
# PyBytes_InternInPlace(), returning either a new string object
# that has been interned, or a new (``owned'') reference to an
# earlier interned string object with the same value.
object PyBytes_Decode(char *s, Py_ssize_t size, char *encoding, char *errors)
# Return value: New reference.
# Create an object by decoding size bytes of the encoded buffer s
# using the codec registered for encoding. encoding and errors
# have the same meaning as the parameters of the same name in the
# unicode() built-in function. The codec to be used is looked up
# using the Python codec registry. Return NULL if an exception was
# raised by the codec.
object PyBytes_AsDecodedObject(object str, char *encoding, char *errors)
# Return value: New reference.
# Decode a string object by passing it to the codec registered for
# encoding and return the result as Python object. encoding and
# errors have the same meaning as the parameters of the same name
# in the string encode() method. The codec to be used is looked up
# using the Python codec registry. Return NULL if an exception was
# raised by the codec.
object PyBytes_Encode(char *s, Py_ssize_t size, char *encoding, char *errors)
# Return value: New reference.
# Encode the char buffer of the given size by passing it to the
# codec registered for encoding and return a Python
# object. encoding and errors have the same meaning as the
# parameters of the same name in the string encode() method. The
# codec to be used is looked up using the Python codec
# registry. Return NULL if an exception was raised by the codec.
object PyBytes_AsEncodedObject(object str, char *encoding, char *errors)
# Return value: New reference.
# Encode a string object using the codec registered for encoding
# and return the result as Python object. encoding and errors have
# the same meaning as the parameters of the same name in the
# string encode() method. The codec to be used is looked up using
# the Python codec registry. Return NULL if an exception was
# raised by the codec.
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/cobject.pxd 0000664 0000000 0000000 00000003026 11446142532 0026571 0 ustar 00root root 0000000 0000000 from cpython.ref cimport PyObject
cdef extern from "Python.h":
###########################################################################
# Warning:
#
# The CObject API is deprecated as of Python 3.1. Please switch to
# the new Capsules API.
###########################################################################
int PyCObject_Check(object p)
# Return true if its argument is a PyCObject.
object PyCObject_FromVoidPtr(void* cobj, void (*destr)(void *))
# Return value: New reference.
#
# Create a PyCObject from the void * cobj. The destr function will
# be called when the object is reclaimed, unless it is NULL.
object PyCObject_FromVoidPtrAndDesc(void* cobj, void* desc, void (*destr)(void *, void *))
# Return value: New reference.
#
# Create a PyCObject from the void * cobj. The destr function will
# be called when the object is reclaimed. The desc argument can be
# used to pass extra callback data for the destructor function.
void* PyCObject_AsVoidPtr(object self) except? NULL
# Return the object void * that the PyCObject self was created with.
void* PyCObject_GetDesc(object self) except? NULL
# Return the description void * that the PyCObject self was created with.
int PyCObject_SetVoidPtr(object self, void* cobj) except 0
# Set the void pointer inside self to cobj. The PyCObject must not
# have an associated destructor. Return true on success, false on
# failure.
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/complex.pxd 0000664 0000000 0000000 00000002744 11446142532 0026635 0 ustar 00root root 0000000 0000000
cdef extern from "Python.h":
ctypedef struct Py_complex
############################################################################
# 7.2.5.2 Complex Numbers as Python Objects
############################################################################
# PyComplexObject
# This subtype of PyObject represents a Python complex number object.
# PyTypeObject PyComplex_Type
# This instance of PyTypeObject represents the Python complex
# number type. It is the same object as complex and
# types.ComplexType.
bint PyComplex_Check(object p)
# Return true if its argument is a PyComplexObject or a subtype of
# PyComplexObject.
bint PyComplex_CheckExact(object p)
# Return true if its argument is a PyComplexObject, but not a subtype of PyComplexObject.
object PyComplex_FromCComplex(Py_complex v)
# Return value: New reference.
# Create a new Python complex number object from a C Py_complex value.
object PyComplex_FromDoubles(double real, double imag)
# Return value: New reference.
# Return a new PyComplexObject object from real and imag.
double PyComplex_RealAsDouble(object op) except? -1
# Return the real part of op as a C double.
double PyComplex_ImagAsDouble(object op) except? -1
# Return the imaginary part of op as a C double.
Py_complex PyComplex_AsCComplex(object op)
# Return the Py_complex value of the complex number op.
#
# Returns (-1+0i) in case of an error
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/dict.pxd 0000664 0000000 0000000 00000015342 11446142532 0026107 0 ustar 00root root 0000000 0000000 from cpython.ref cimport PyObject
cdef extern from "Python.h":
############################################################################
# 7.4.1 Dictionary Objects
############################################################################
# PyDictObject
#
# This subtype of PyObject represents a Python dictionary object
# (i.e. the 'dict' type).
# PyTypeObject PyDict_Type
#
# This instance of PyTypeObject represents the Python dictionary
# type. This is exposed to Python programs as dict and
# types.DictType.
bint PyDict_Check(object p)
# Return true if p is a dict object or an instance of a subtype of
# the dict type.
bint PyDict_CheckExact(object p)
# Return true if p is a dict object, but not an instance of a
# subtype of the dict type.
object PyDict_New()
# Return value: New reference.
# Return a new empty dictionary, or NULL on failure.
object PyDictProxy_New(object dict)
# Return value: New reference.
# Return a proxy object for a mapping which enforces read-only
# behavior. This is normally used to create a proxy to prevent
# modification of the dictionary for non-dynamic class types.
void PyDict_Clear(object p)
# Empty an existing dictionary of all key-value pairs.
int PyDict_Contains(object p, object key) except -1
# Determine if dictionary p contains key. If an item in p is
# matches key, return 1, otherwise return 0. On error, return
# -1. This is equivalent to the Python expression "key in p".
object PyDict_Copy(object p)
# Return value: New reference.
# Return a new dictionary that contains the same key-value pairs as p.
int PyDict_SetItem(object p, object key, object val) except -1
# Insert value into the dictionary p with a key of key. key must
# be hashable; if it isn't, TypeError will be raised. Return 0 on
# success or -1 on failure.
int PyDict_SetItemString(object p, char *key, object val) except -1
# Insert value into the dictionary p using key as a key. key
# should be a char*. The key object is created using
# PyString_FromString(key). Return 0 on success or -1 on failure.
int PyDict_DelItem(object p, object key) except -1
# Remove the entry in dictionary p with key key. key must be
# hashable; if it isn't, TypeError is raised. Return 0 on success
# or -1 on failure.
int PyDict_DelItemString(object p, char *key) except -1
# Remove the entry in dictionary p which has a key specified by
# the string key. Return 0 on success or -1 on failure.
PyObject* PyDict_GetItem(object p, object key)
# Return value: Borrowed reference.
# Return the object from dictionary p which has a key key. Return
# NULL if the key key is not present, but without setting an
# exception.
PyObject* PyDict_GetItemString(object p, char *key)
# Return value: Borrowed reference.
# This is the same as PyDict_GetItem(), but key is specified as a
# char*, rather than a PyObject*.
object PyDict_Items(object p)
# Return value: New reference.
# Return a PyListObject containing all the items from the
# dictionary, as in the dictionary method items() (see the Python
# Library Reference).
object PyDict_Keys(object p)
# Return value: New reference.
# Return a PyListObject containing all the keys from the
# dictionary, as in the dictionary method keys() (see the Python
# Library Reference).
object PyDict_Values(object p)
# Return value: New reference.
# Return a PyListObject containing all the values from the
# dictionary p, as in the dictionary method values() (see the
# Python Library Reference).
Py_ssize_t PyDict_Size(object p) except -1
# Return the number of items in the dictionary. This is equivalent
# to "len(p)" on a dictionary.
int PyDict_Next(object p, Py_ssize_t *ppos, PyObject* *pkey, PyObject* *pvalue)
# Iterate over all key-value pairs in the dictionary p. The int
# referred to by ppos must be initialized to 0 prior to the first
# call to this function to start the iteration; the function
# returns true for each pair in the dictionary, and false once all
# pairs have been reported. The parameters pkey and pvalue should
# either point to PyObject* variables that will be filled in with
# each key and value, respectively, or may be NULL. Any references
# returned through them are borrowed. ppos should not be altered
# during iteration. Its value represents offsets within the
# internal dictionary structure, and since the structure is
# sparse, the offsets are not consecutive.
# For example:
#
#object key, *value;
#int pos = 0;
#
#while (PyDict_Next(self->dict, &pos, &key, &value)) {
# /* do something interesting with the values... */
# ...
#}
# The dictionary p should not be mutated during iteration. It is
# safe (since Python 2.1) to modify the values of the keys as you
# iterate over the dictionary, but only so long as the set of keys
# does not change. For example:
# object key, *value;
# int pos = 0;
# while (PyDict_Next(self->dict, &pos, &key, &value)) {
# int i = PyInt_AS_LONG(value) + 1;
# object o = PyInt_FromLong(i);
# if (o == NULL)
# return -1;
# if (PyDict_SetItem(self->dict, key, o) < 0) {
# Py_DECREF(o);
# return -1;
# }
# Py_DECREF(o);
# }
int PyDict_Merge(object a, object b, int override) except -1
# Iterate over mapping object b adding key-value pairs to
# dictionary a. b may be a dictionary, or any object supporting
# PyMapping_Keys() and PyObject_GetItem(). If override is true,
# existing pairs in a will be replaced if a matching key is found
# in b, otherwise pairs will only be added if there is not a
# matching key in a. Return 0 on success or -1 if an exception was
# raised.
int PyDict_Update(object a, object b) except -1
# This is the same as PyDict_Merge(a, b, 1) in C, or a.update(b)
# in Python. Return 0 on success or -1 if an exception was raised.
int PyDict_MergeFromSeq2(object a, object seq2, int override) except -1
# Update or merge into dictionary a, from the key-value pairs in
# seq2. seq2 must be an iterable object producing iterable objects
# of length 2, viewed as key-value pairs. In case of duplicate
# keys, the last wins if override is true, else the first
# wins. Return 0 on success or -1 if an exception was
# raised. Equivalent Python (except for the return value):
#
#def PyDict_MergeFromSeq2(a, seq2, override):
# for key, value in seq2:
# if override or key not in a:
# a[key] = value
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/exc.pxd 0000664 0000000 0000000 00000031636 11446142532 0025747 0 ustar 00root root 0000000 0000000 from cpython.ref cimport PyObject
cdef extern from "Python.h":
#####################################################################
# 3. Exception Handling
#####################################################################
# The functions described in this chapter will let you handle and
# raise Python exceptions. It is important to understand some of
# the basics of Python exception handling. It works somewhat like
# the Unix errno variable: there is a global indicator (per
# thread) of the last error that occurred. Most functions don't
# clear this on success, but will set it to indicate the cause of
# the error on failure. Most functions also return an error
# indicator, usually NULL if they are supposed to return a
# pointer, or -1 if they return an integer (exception: the
# PyArg_*() functions return 1 for success and 0 for failure).
# When a function must fail because some function it called
# failed, it generally doesn't set the error indicator; the
# function it called already set it. It is responsible for either
# handling the error and clearing the exception or returning after
# cleaning up any resources it holds (such as object references or
# memory allocations); it should not continue normally if it is
# not prepared to handle the error. If returning due to an error,
# it is important to indicate to the caller that an error has been
# set. If the error is not handled or carefully propagated,
# additional calls into the Python/C API may not behave as
# intended and may fail in mysterious ways.
# The error indicator consists of three Python objects
# corresponding to the Python variables sys.exc_type,
# sys.exc_value and sys.exc_traceback. API functions exist to
# interact with the error indicator in various ways. There is a
# separate error indicator for each thread.
void PyErr_Print()
# Print a standard traceback to sys.stderr and clear the error
# indicator. Call this function only when the error indicator is
# set. (Otherwise it will cause a fatal error!)
PyObject* PyErr_Occurred()
# Return value: Borrowed reference.
# Test whether the error indicator is set. If set, return the
# exception type (the first argument to the last call to one of
# the PyErr_Set*() functions or to PyErr_Restore()). If not set,
# return NULL. You do not own a reference to the return value, so
# you do not need to Py_DECREF() it. Note: Do not compare the
# return value to a specific exception; use
# PyErr_ExceptionMatches() instead, shown below. (The comparison
# could easily fail since the exception may be an instance instead
# of a class, in the case of a class exception, or it may the a
# subclass of the expected exception.)
bint PyErr_ExceptionMatches(object exc)
# Equivalent to "PyErr_GivenExceptionMatches(PyErr_Occurred(),
# exc)". This should only be called when an exception is actually
# set; a memory access violation will occur if no exception has
# been raised.
bint PyErr_GivenExceptionMatches(object given, object exc)
# Return true if the given exception matches the exception in
# exc. If exc is a class object, this also returns true when given
# is an instance of a subclass. If exc is a tuple, all exceptions
# in the tuple (and recursively in subtuples) are searched for a
# match. If given is NULL, a memory access violation will occur.
void PyErr_NormalizeException(PyObject** exc, PyObject** val, PyObject** tb)
# Under certain circumstances, the values returned by
# PyErr_Fetch() below can be ``unnormalized'', meaning that *exc
# is a class object but *val is not an instance of the same
# class. This function can be used to instantiate the class in
# that case. If the values are already normalized, nothing
# happens. The delayed normalization is implemented to improve
# performance.
void PyErr_Clear()
# Clear the error indicator. If the error indicator is not set, there is no effect.
void PyErr_Fetch(PyObject** ptype, PyObject** pvalue, PyObject** ptraceback)
# Retrieve the error indicator into three variables whose
# addresses are passed. If the error indicator is not set, set all
# three variables to NULL. If it is set, it will be cleared and
# you own a reference to each object retrieved. The value and
# traceback object may be NULL even when the type object is
# not. Note: This function is normally only used by code that
# needs to handle exceptions or by code that needs to save and
# restore the error indicator temporarily.
void PyErr_Restore(PyObject* type, PyObject* value, PyObject* traceback)
# Set the error indicator from the three objects. If the error
# indicator is already set, it is cleared first. If the objects
# are NULL, the error indicator is cleared. Do not pass a NULL
# type and non-NULL value or traceback. The exception type should
# be a class. Do not pass an invalid exception type or
# value. (Violating these rules will cause subtle problems later.)
# This call takes away a reference to each object: you must own a
# reference to each object before the call and after the call you
# no longer own these references. (If you don't understand this,
# don't use this function. I warned you.) Note: This function is
# normally only used by code that needs to save and restore the
# error indicator temporarily; use PyErr_Fetch() to save the
# current exception state.
void PyErr_SetString(object type, char *message)
# This is the most common way to set the error indicator. The
# first argument specifies the exception type; it is normally one
# of the standard exceptions, e.g. PyExc_RuntimeError. You need
# not increment its reference count. The second argument is an
# error message; it is converted to a string object.
void PyErr_SetObject(object type, object value)
# This function is similar to PyErr_SetString() but lets you
# specify an arbitrary Python object for the ``value'' of the
# exception.
PyObject* PyErr_Format(object exception, char *format, ...) except NULL
# Return value: Always NULL.
# This function sets the error indicator and returns
# NULL. exception should be a Python exception (class, not an
# instance). format should be a string, containing format codes,
# similar to printf(). The width.precision before a format code is
# parsed, but the width part is ignored.
void PyErr_SetNone(object type)
# This is a shorthand for "PyErr_SetObject(type, Py_None)".
int PyErr_BadArgument() except 0
# This is a shorthand for "PyErr_SetString(PyExc_TypeError,
# message)", where message indicates that a built-in operation was
# invoked with an illegal argument. It is mostly for internal use.
PyObject* PyErr_NoMemory() except NULL
# Return value: Always NULL.
# This is a shorthand for "PyErr_SetNone(PyExc_MemoryError)"; it
# returns NULL so an object allocation function can write "return
# PyErr_NoMemory();" when it runs out of memory.
PyObject* PyErr_SetFromErrno(object type) except NULL
# Return value: Always NULL.
# This is a convenience function to raise an exception when a C
# library function has returned an error and set the C variable
# errno. It constructs a tuple object whose first item is the
# integer errno value and whose second item is the corresponding
# error message (gotten from strerror()), and then calls
# "PyErr_SetObject(type, object)". On Unix, when the errno value
# is EINTR, indicating an interrupted system call, this calls
# PyErr_CheckSignals(), and if that set the error indicator,
# leaves it set to that. The function always returns NULL, so a
# wrapper function around a system call can write "return
# PyErr_SetFromErrno(type);" when the system call returns an
# error.
PyObject* PyErr_SetFromErrnoWithFilename(object type, char *filename) except NULL
# Return value: Always NULL. Similar to PyErr_SetFromErrno(),
# with the additional behavior that if filename is not NULL, it is
# passed to the constructor of type as a third parameter. In the
# case of exceptions such as IOError and OSError, this is used to
# define the filename attribute of the exception instance.
PyObject* PyErr_SetFromWindowsErr(int ierr) except NULL
# Return value: Always NULL. This is a convenience function to
# raise WindowsError. If called with ierr of 0, the error code
# returned by a call to GetLastError() is used instead. It calls
# the Win32 function FormatMessage() to retrieve the Windows
# description of error code given by ierr or GetLastError(), then
# it constructs a tuple object whose first item is the ierr value
# and whose second item is the corresponding error message (gotten
# from FormatMessage()), and then calls
# "PyErr_SetObject(PyExc_WindowsError, object)". This function
# always returns NULL. Availability: Windows.
PyObject* PyErr_SetExcFromWindowsErr(object type, int ierr) except NULL
# Return value: Always NULL. Similar to
# PyErr_SetFromWindowsErr(), with an additional parameter
# specifying the exception type to be raised. Availability:
# Windows. New in version 2.3.
PyObject* PyErr_SetFromWindowsErrWithFilename(int ierr, char *filename) except NULL
# Return value: Always NULL. Similar to
# PyErr_SetFromWindowsErr(), with the additional behavior that if
# filename is not NULL, it is passed to the constructor of
# WindowsError as a third parameter. Availability: Windows.
PyObject* PyErr_SetExcFromWindowsErrWithFilename(object type, int ierr, char *filename) except NULL
# Return value: Always NULL.
# Similar to PyErr_SetFromWindowsErrWithFilename(), with an
# additional parameter specifying the exception type to be
# raised. Availability: Windows.
void PyErr_BadInternalCall()
# This is a shorthand for "PyErr_SetString(PyExc_TypeError,
# message)", where message indicates that an internal operation
# (e.g. a Python/C API function) was invoked with an illegal
# argument. It is mostly for internal use.
int PyErr_WarnEx(object category, char *message, int stacklevel) except -1
# Issue a warning message. The category argument is a warning
# category (see below) or NULL; the message argument is a message
# string. stacklevel is a positive number giving a number of stack
# frames; the warning will be issued from the currently executing
# line of code in that stack frame. A stacklevel of 1 is the
# function calling PyErr_WarnEx(), 2 is the function above that,
# and so forth.
int PyErr_WarnExplicit(object category, char *message, char *filename, int lineno, char *module, object registry) except -1
# Issue a warning message with explicit control over all warning
# attributes. This is a straightforward wrapper around the Python
# function warnings.warn_explicit(), see there for more
# information. The module and registry arguments may be set to
# NULL to get the default effect described there.
int PyErr_CheckSignals() except -1
# This function interacts with Python's signal handling. It checks
# whether a signal has been sent to the processes and if so,
# invokes the corresponding signal handler. If the signal module
# is supported, this can invoke a signal handler written in
# Python. In all cases, the default effect for SIGINT is to raise
# the KeyboardInterrupt exception. If an exception is raised the
# error indicator is set and the function returns 1; otherwise the
# function returns 0. The error indicator may or may not be
# cleared if it was previously set.
void PyErr_SetInterrupt()
# This function simulates the effect of a SIGINT signal arriving
# -- the next time PyErr_CheckSignals() is called,
# KeyboardInterrupt will be raised. It may be called without
# holding the interpreter lock.
object PyErr_NewException(char *name, object base, object dict)
# Return value: New reference.
# This utility function creates and returns a new exception
# object. The name argument must be the name of the new exception,
# a C string of the form module.class. The base and dict arguments
# are normally NULL. This creates a class object derived from
# Exception (accessible in C as PyExc_Exception).
void PyErr_WriteUnraisable(object obj)
# This utility function prints a warning message to sys.stderr
# when an exception has been set but it is impossible for the
# interpreter to actually raise the exception. It is used, for
# example, when an exception occurs in an __del__() method.
#
# The function is called with a single argument obj that
# identifies the context in which the unraisable exception
# occurred. The repr of obj will be printed in the warning
# message.
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/float.pxd 0000664 0000000 0000000 00000002642 11446142532 0026270 0 ustar 00root root 0000000 0000000 cdef extern from "Python.h":
############################################################################
# 7.2.3
############################################################################
# PyFloatObject
#
# This subtype of PyObject represents a Python floating point object.
# PyTypeObject PyFloat_Type
#
# This instance of PyTypeObject represents the Python floating
# point type. This is the same object as float and
# types.FloatType.
bint PyFloat_Check(object p)
# Return true if its argument is a PyFloatObject or a subtype of
# PyFloatObject.
bint PyFloat_CheckExact(object p)
# Return true if its argument is a PyFloatObject, but not a
# subtype of PyFloatObject.
object PyFloat_FromString(object str, char **pend)
# Return value: New reference.
# Create a PyFloatObject object based on the string value in str,
# or NULL on failure. The pend argument is ignored. It remains
# only for backward compatibility.
object PyFloat_FromDouble(double v)
# Return value: New reference.
# Create a PyFloatObject object from v, or NULL on failure.
double PyFloat_AsDouble(object pyfloat) except? -1
# Return a C double representation of the contents of pyfloat.
double PyFloat_AS_DOUBLE(object pyfloat) except? -1
# Return a C double representation of the contents of pyfloat, but
# without error checking.
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/function.pxd 0000664 0000000 0000000 00000005167 11446142532 0027015 0 ustar 00root root 0000000 0000000 from cpython.ref cimport PyObject
cdef extern from "Python.h":
############################################################################
# 7.5.3 Function Objects
############################################################################
# There are a few functions specific to Python functions.
# PyFunctionObject
#
# The C structure used for functions.
# PyTypeObject PyFunction_Type
#
# This is an instance of PyTypeObject and represents the Python
# function type. It is exposed to Python programmers as
# types.FunctionType.
bint PyFunction_Check(object o)
# Return true if o is a function object (has type
# PyFunction_Type). The parameter must not be NULL.
object PyFunction_New(object code, object globals)
# Return value: New reference.
# Return a new function object associated with the code object
# code. globals must be a dictionary with the global variables
# accessible to the function.
# The function's docstring, name and __module__ are retrieved from
# the code object, the argument defaults and closure are set to
# NULL.
PyObject* PyFunction_GetCode(object op) except? NULL
# Return value: Borrowed reference.
# Return the code object associated with the function object op.
PyObject* PyFunction_GetGlobals(object op) except? NULL
# Return value: Borrowed reference.
# Return the globals dictionary associated with the function object op.
PyObject* PyFunction_GetModule(object op) except? NULL
# Return value: Borrowed reference.
# Return the __module__ attribute of the function object op. This
# is normally a string containing the module name, but can be set
# to any other object by Python code.
PyObject* PyFunction_GetDefaults(object op) except? NULL
# Return value: Borrowed reference.
# Return the argument default values of the function object
# op. This can be a tuple of arguments or NULL.
int PyFunction_SetDefaults(object op, object defaults) except -1
# Set the argument default values for the function object
# op. defaults must be Py_None or a tuple.
# Raises SystemError and returns -1 on failure.
PyObject* PyFunction_GetClosure(object op) except? NULL
# Return value: Borrowed reference.
# Return the closure associated with the function object op. This
# can be NULL or a tuple of cell objects.
int PyFunction_SetClosure(object op, object closure) except -1
# Set the closure associated with the function object op. closure
# must be Py_None or a tuple of cell objects.
# Raises SystemError and returns -1 on failure.
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/getargs.pxd 0000664 0000000 0000000 00000001451 11446142532 0026614 0 ustar 00root root 0000000 0000000 from cpython.ref cimport PyObject
cdef extern from "Python.h":
#####################################################################
# 5.5 Parsing arguments and building values
#####################################################################
ctypedef struct va_list
int PyArg_ParseTuple(object args, char *format, ...) except 0
int PyArg_VaParse(object args, char *format, va_list vargs) except 0
int PyArg_ParseTupleAndKeywords(object args, object kw, char *format, char *keywords[], ...) except 0
int PyArg_VaParseTupleAndKeywords(object args, object kw, char *format, char *keywords[], va_list vargs) except 0
int PyArg_Parse(object args, char *format, ...) except 0
int PyArg_UnpackTuple(object args, char *name, Py_ssize_t min, Py_ssize_t max, ...) except 0
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/instance.pxd 0000664 0000000 0000000 00000001742 11446142532 0026767 0 ustar 00root root 0000000 0000000 cdef extern from "Python.h":
############################################################################
# 7.5.2 Instance Objects
############################################################################
# PyTypeObject PyInstance_Type
#
# Type object for class instances.
int PyInstance_Check(object obj)
# Return true if obj is an instance.
object PyInstance_New(object cls, object arg, object kw)
# Return value: New reference.
# Create a new instance of a specific class. The parameters arg
# and kw are used as the positional and keyword parameters to the
# object's constructor.
object PyInstance_NewRaw(object cls, object dict)
# Return value: New reference.
# Create a new instance of a specific class without calling its
# constructor. class is the class of new object. The dict
# parameter will be used as the object's __dict__; if NULL, a new
# dictionary will be created for the instance.
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/int.pxd 0000664 0000000 0000000 00000007243 11446142532 0025757 0 ustar 00root root 0000000 0000000 cdef extern from "Python.h":
ctypedef unsigned long long PY_LONG_LONG
############################################################################
# Integer Objects
############################################################################
# PyTypeObject PyInt_Type
# This instance of PyTypeObject represents the Python plain
# integer type. This is the same object as int and types.IntType.
bint PyInt_Check(object o)
# Return true if o is of type PyInt_Type or a subtype of
# PyInt_Type.
bint PyInt_CheckExact(object o)
# Return true if o is of type PyInt_Type, but not a subtype of
# PyInt_Type.
object PyInt_FromString(char *str, char **pend, int base)
# Return value: New reference.
# Return a new PyIntObject or PyLongObject based on the string
# value in str, which is interpreted according to the radix in
# base. If pend is non-NULL, *pend will point to the first
# character in str which follows the representation of the
# number. If base is 0, the radix will be determined based on the
# leading characters of str: if str starts with '0x' or '0X',
# radix 16 will be used; if str starts with '0', radix 8 will be
# used; otherwise radix 10 will be used. If base is not 0, it must
# be between 2 and 36, inclusive. Leading spaces are ignored. If
# there are no digits, ValueError will be raised. If the string
# represents a number too large to be contained within the
# machine's long int type and overflow warnings are being
# suppressed, a PyLongObject will be returned. If overflow
# warnings are not being suppressed, NULL will be returned in this
# case.
object PyInt_FromLong(long ival)
# Return value: New reference.
# Create a new integer object with a value of ival.
# The current implementation keeps an array of integer objects for
# all integers between -5 and 256, when you create an int in that
# range you actually just get back a reference to the existing
# object. So it should be possible to change the value of 1. I
# suspect the behaviour of Python in this case is undefined. :-)
object PyInt_FromSsize_t(Py_ssize_t ival)
# Return value: New reference.
# Create a new integer object with a value of ival. If the value
# exceeds LONG_MAX, a long integer object is returned.
long PyInt_AsLong(object io) except? -1
# Will first attempt to cast the object to a PyIntObject, if it is
# not already one, and then return its value. If there is an
# error, -1 is returned, and the caller should check
# PyErr_Occurred() to find out whether there was an error, or
# whether the value just happened to be -1.
long PyInt_AS_LONG(object io)
# Return the value of the object io. No error checking is performed.
unsigned long PyInt_AsUnsignedLongMask(object io) except? -1
# Will first attempt to cast the object to a PyIntObject or
# PyLongObject, if it is not already one, and then return its
# value as unsigned long. This function does not check for
# overflow.
PY_LONG_LONG PyInt_AsUnsignedLongLongMask(object io) except? -1
# Will first attempt to cast the object to a PyIntObject or
# PyLongObject, if it is not already one, and then return its
# value as unsigned long long, without checking for overflow.
Py_ssize_t PyInt_AsSsize_t(object io) except? -1
# Will first attempt to cast the object to a PyIntObject or
# PyLongObject, if it is not already one, and then return its
# value as Py_ssize_t.
long PyInt_GetMax()
# Return the system's idea of the largest integer it can handle
# (LONG_MAX, as defined in the system header files).
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/iterator.pxd 0000664 0000000 0000000 00000002450 11446142532 0027011 0 ustar 00root root 0000000 0000000 cdef extern from "Python.h":
############################################################################
# 6.5 Iterator Protocol
############################################################################
bint PyIter_Check(object o)
# Return true if the object o supports the iterator protocol.
object PyIter_Next(object o)
# Return value: New reference.
# Return the next value from the iteration o. If the object is an
# iterator, this retrieves the next value from the iteration, and
# returns NULL with no exception set if there are no remaining
# items. If the object is not an iterator, TypeError is raised, or
# if there is an error in retrieving the item, returns NULL and
# passes along the exception.
# To write a loop which iterates over an iterator, the C code should look something like this:
# PyObject *iterator = PyObject_GetIter(obj);
# PyObject *item;
# if (iterator == NULL) {
# /* propagate error */
# }
# while (item = PyIter_Next(iterator)) {
# /* do something with item */
# ...
# /* release reference when done */
# Py_DECREF(item);
# }
# Py_DECREF(iterator);
# if (PyErr_Occurred()) {
# /* propagate error */
# }
# else {
# /* continue doing useful work */
# }
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/list.pxd 0000664 0000000 0000000 00000010011 11446142532 0026123 0 ustar 00root root 0000000 0000000 from cpython.ref cimport PyObject
cdef extern from "Python.h":
############################################################################
# Lists
############################################################################
object PyList_New(Py_ssize_t len)
# Return a new list of length len on success, or NULL on failure.
#
# Note: If length is greater than zero, the returned list object's
# items are set to NULL. Thus you cannot use abstract API
# functions such as PySequence_SetItem() or expose the object to
# Python code before setting all items to a real object with
# PyList_SetItem().
bint PyList_Check(object p)
# Return true if p is a list object or an instance of a subtype of
# the list type.
bint PyList_CheckExact(object p)
# Return true if p is a list object, but not an instance of a
# subtype of the list type.
Py_ssize_t PyList_Size(object list) except -1
# Return the length of the list object in list; this is equivalent
# to "len(list)" on a list object.
Py_ssize_t PyList_GET_SIZE(object list)
# Macro form of PyList_Size() without error checking.
PyObject* PyList_GetItem(object list, Py_ssize_t index) except NULL
# Return value: Borrowed reference.
# Return the object at position pos in the list pointed to by
# p. The position must be positive, indexing from the end of the
# list is not supported. If pos is out of bounds, return NULL and
# set an IndexError exception.
PyObject* PyList_GET_ITEM(object list, Py_ssize_t i)
# Return value: Borrowed reference.
# Macro form of PyList_GetItem() without error checking.
int PyList_SetItem(object list, Py_ssize_t index, object item) except -1
# Set the item at index index in list to item. Return 0 on success
# or -1 on failure. Note: This function ``steals'' a reference to
# item and discards a reference to an item already in the list at
# the affected position.
void PyList_SET_ITEM(object list, Py_ssize_t i, object o)
# Macro form of PyList_SetItem() without error checking. This is
# normally only used to fill in new lists where there is no
# previous content. Note: This function ``steals'' a reference to
# item, and, unlike PyList_SetItem(), does not discard a reference
# to any item that it being replaced; any reference in list at
# position i will be *leaked*.
int PyList_Insert(object list, Py_ssize_t index, object item) except -1
# Insert the item item into list list in front of index
# index. Return 0 if successful; return -1 and set an exception if
# unsuccessful. Analogous to list.insert(index, item).
int PyList_Append(object list, object item) except -1
# Append the object item at the end of list list. Return 0 if
# successful; return -1 and set an exception if
# unsuccessful. Analogous to list.append(item).
object PyList_GetSlice(object list, Py_ssize_t low, Py_ssize_t high)
# Return value: New reference.
# Return a list of the objects in list containing the objects
# between low and high. Return NULL and set an exception if
# unsuccessful. Analogous to list[low:high].
int PyList_SetSlice(object list, Py_ssize_t low, Py_ssize_t high, object itemlist) except -1
# Set the slice of list between low and high to the contents of
# itemlist. Analogous to list[low:high] = itemlist. The itemlist
# may be NULL, indicating the assignment of an empty list (slice
# deletion). Return 0 on success, -1 on failure.
int PyList_Sort(object list) except -1
# Sort the items of list in place. Return 0 on success, -1 on
# failure. This is equivalent to "list.sort()".
int PyList_Reverse(object list) except -1
# Reverse the items of list in place. Return 0 on success, -1 on
# failure. This is the equivalent of "list.reverse()".
object PyList_AsTuple(object list)
# Return value: New reference.
# Return a new tuple object containing the contents of list;
# equivalent to "tuple(list)".
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/long.pxd 0000664 0000000 0000000 00000012163 11446142532 0026121 0 ustar 00root root 0000000 0000000
cdef extern from "Python.h":
ctypedef long long PY_LONG_LONG
ctypedef unsigned long long uPY_LONG_LONG
############################################################################
# 7.2.3 Long Integer Objects
############################################################################
# PyLongObject
#
# This subtype of PyObject represents a Python long integer object.
# PyTypeObject PyLong_Type
#
# This instance of PyTypeObject represents the Python long integer
# type. This is the same object as long and types.LongType.
bint PyLong_Check(object p)
# Return true if its argument is a PyLongObject or a subtype of PyLongObject.
bint PyLong_CheckExact(object p)
# Return true if its argument is a PyLongObject, but not a subtype of PyLongObject.
object PyLong_FromLong(long v)
# Return value: New reference.
# Return a new PyLongObject object from v, or NULL on failure.
object PyLong_FromUnsignedLong(unsigned long v)
# Return value: New reference.
# Return a new PyLongObject object from a C unsigned long, or NULL on failure.
object PyLong_FromLongLong(PY_LONG_LONG v)
# Return value: New reference.
# Return a new PyLongObject object from a C long long, or NULL on failure.
object PyLong_FromUnsignedLongLong(uPY_LONG_LONG v)
# Return value: New reference.
# Return a new PyLongObject object from a C unsigned long long, or NULL on failure.
object PyLong_FromDouble(double v)
# Return value: New reference.
# Return a new PyLongObject object from the integer part of v, or NULL on failure.
object PyLong_FromString(char *str, char **pend, int base)
# Return value: New reference.
# Return a new PyLongObject based on the string value in str,
# which is interpreted according to the radix in base. If pend is
# non-NULL, *pend will point to the first character in str which
# follows the representation of the number. If base is 0, the
# radix will be determined based on the leading characters of str:
# if str starts with '0x' or '0X', radix 16 will be used; if str
# starts with '0', radix 8 will be used; otherwise radix 10 will
# be used. If base is not 0, it must be between 2 and 36,
# inclusive. Leading spaces are ignored. If there are no digits,
# ValueError will be raised.
object PyLong_FromUnicode(Py_UNICODE *u, Py_ssize_t length, int base)
# Return value: New reference.
# Convert a sequence of Unicode digits to a Python long integer
# value. The first parameter, u, points to the first character of
# the Unicode string, length gives the number of characters, and
# base is the radix for the conversion. The radix must be in the
# range [2, 36]; if it is out of range, ValueError will be
# raised.
object PyLong_FromVoidPtr(void *p)
# Return value: New reference.
# Create a Python integer or long integer from the pointer p. The
# pointer value can be retrieved from the resulting value using
# PyLong_AsVoidPtr(). If the integer is larger than LONG_MAX, a
# positive long integer is returned.
long PyLong_AsLong(object pylong) except? -1
# Return a C long representation of the contents of pylong. If
# pylong is greater than LONG_MAX, an OverflowError is raised.
unsigned long PyLong_AsUnsignedLong(object pylong) except? -1
# Return a C unsigned long representation of the contents of
# pylong. If pylong is greater than ULONG_MAX, an OverflowError is
# raised.
PY_LONG_LONG PyLong_AsLongLong(object pylong) except? -1
# Return a C long long from a Python long integer. If pylong
# cannot be represented as a long long, an OverflowError will be
# raised.
uPY_LONG_LONG PyLong_AsUnsignedLongLong(object pylong) except? -1
#unsigned PY_LONG_LONG PyLong_AsUnsignedLongLong(object pylong)
# Return a C unsigned long long from a Python long integer. If
# pylong cannot be represented as an unsigned long long, an
# OverflowError will be raised if the value is positive, or a
# TypeError will be raised if the value is negative.
unsigned long PyLong_AsUnsignedLongMask(object io) except? -1
# Return a C unsigned long from a Python long integer, without
# checking for overflow.
uPY_LONG_LONG PyLong_AsUnsignedLongLongMask(object io) except? -1
#unsigned PY_LONG_LONG PyLong_AsUnsignedLongLongMask(object io)
# Return a C unsigned long long from a Python long integer,
# without checking for overflow.
double PyLong_AsDouble(object pylong) except? -1.0
# Return a C double representation of the contents of pylong. If
# pylong cannot be approximately represented as a double, an
# OverflowError exception is raised and -1.0 will be returned.
void* PyLong_AsVoidPtr(object pylong) except? NULL
# Convert a Python integer or long integer pylong to a C void
# pointer. If pylong cannot be converted, an OverflowError will be
# raised. This is only assured to produce a usable void pointer
# for values created with PyLong_FromVoidPtr(). For values outside
# 0..LONG_MAX, both signed and unsigned integers are acccepted.
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/mapping.pxd 0000664 0000000 0000000 00000005205 11446142532 0026614 0 ustar 00root root 0000000 0000000 cdef extern from "Python.h":
############################################################################
# 6.4 Mapping Protocol
############################################################################
bint PyMapping_Check(object o)
# Return 1 if the object provides mapping protocol, and 0
# otherwise. This function always succeeds.
Py_ssize_t PyMapping_Length(object o) except -1
# Returns the number of keys in object o on success, and -1 on
# failure. For objects that do not provide mapping protocol, this
# is equivalent to the Python expression "len(o)".
int PyMapping_DelItemString(object o, char *key) except -1
# Remove the mapping for object key from the object o. Return -1
# on failure. This is equivalent to the Python statement "del
# o[key]".
int PyMapping_DelItem(object o, object key) except -1
# Remove the mapping for object key from the object o. Return -1
# on failure. This is equivalent to the Python statement "del
# o[key]".
bint PyMapping_HasKeyString(object o, char *key)
# On success, return 1 if the mapping object has the key key and 0
# otherwise. This is equivalent to the Python expression
# "o.has_key(key)". This function always succeeds.
bint PyMapping_HasKey(object o, object key)
# Return 1 if the mapping object has the key key and 0
# otherwise. This is equivalent to the Python expression
# "o.has_key(key)". This function always succeeds.
object PyMapping_Keys(object o)
# Return value: New reference.
# On success, return a list of the keys in object o. On failure,
# return NULL. This is equivalent to the Python expression
# "o.keys()".
object PyMapping_Values(object o)
# Return value: New reference.
# On success, return a list of the values in object o. On failure,
# return NULL. This is equivalent to the Python expression
# "o.values()".
object PyMapping_Items(object o)
# Return value: New reference.
# On success, return a list of the items in object o, where each
# item is a tuple containing a key-value pair. On failure, return
# NULL. This is equivalent to the Python expression "o.items()".
object PyMapping_GetItemString(object o, char *key)
# Return value: New reference.
# Return element of o corresponding to the object key or NULL on
# failure. This is the equivalent of the Python expression
# "o[key]".
int PyMapping_SetItemString(object o, char *key, object v) except -1
# Map the object key to the value v in object o. Returns -1 on
# failure. This is the equivalent of the Python statement "o[key]
# = v".
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/mem.pxd 0000664 0000000 0000000 00000007174 11446142532 0025746 0 ustar 00root root 0000000 0000000 cdef extern from "Python.h":
#####################################################################
# 9.2 Memory Interface
#####################################################################
# You are definitely *supposed* to use these: "In most situations,
# however, it is recommended to allocate memory from the Python
# heap specifically because the latter is under control of the
# Python memory manager. For example, this is required when the
# interpreter is extended with new object types written in
# C. Another reason for using the Python heap is the desire to
# inform the Python memory manager about the memory needs of the
# extension module. Even when the requested memory is used
# exclusively for internal, highly-specific purposes, delegating
# all memory requests to the Python memory manager causes the
# interpreter to have a more accurate image of its memory
# footprint as a whole. Consequently, under certain circumstances,
# the Python memory manager may or may not trigger appropriate
# actions, like garbage collection, memory compaction or other
# preventive procedures. Note that by using the C library
# allocator as shown in the previous example, the allocated memory
# for the I/O buffer escapes completely the Python memory
# manager."
# The following function sets, modeled after the ANSI C standard,
# but specifying behavior when requesting zero bytes, are
# available for allocating and releasing memory from the Python
# heap:
void* PyMem_Malloc(size_t n)
# Allocates n bytes and returns a pointer of type void* to the
# allocated memory, or NULL if the request fails. Requesting zero
# bytes returns a distinct non-NULL pointer if possible, as if
# PyMem_Malloc(1) had been called instead. The memory will not
# have been initialized in any way.
void* PyMem_Realloc(void *p, size_t n)
# Resizes the memory block pointed to by p to n bytes. The
# contents will be unchanged to the minimum of the old and the new
# sizes. If p is NULL, the call is equivalent to PyMem_Malloc(n);
# else if n is equal to zero, the memory block is resized but is
# not freed, and the returned pointer is non-NULL. Unless p is
# NULL, it must have been returned by a previous call to
# PyMem_Malloc() or PyMem_Realloc().
void PyMem_Free(void *p)
# Frees the memory block pointed to by p, which must have been
# returned by a previous call to PyMem_Malloc() or
# PyMem_Realloc(). Otherwise, or if PyMem_Free(p) has been called
# before, undefined behavior occurs. If p is NULL, no operation is
# performed.
# The following type-oriented macros are provided for
# convenience. Note that TYPE refers to any C type.
# TYPE* PyMem_New(TYPE, size_t n)
# Same as PyMem_Malloc(), but allocates (n * sizeof(TYPE)) bytes
# of memory. Returns a pointer cast to TYPE*. The memory will not
# have been initialized in any way.
# TYPE* PyMem_Resize(void *p, TYPE, size_t n)
# Same as PyMem_Realloc(), but the memory block is resized to (n *
# sizeof(TYPE)) bytes. Returns a pointer cast to TYPE*.
void PyMem_Del(void *p)
# Same as PyMem_Free().
# In addition, the following macro sets are provided for calling
# the Python memory allocator directly, without involving the C
# API functions listed above. However, note that their use does
# not preserve binary compatibility across Python versions and is
# therefore deprecated in extension modules.
# PyMem_MALLOC(), PyMem_REALLOC(), PyMem_FREE().
# PyMem_NEW(), PyMem_RESIZE(), PyMem_DEL().
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/method.pxd 0000664 0000000 0000000 00000004226 11446142532 0026443 0 ustar 00root root 0000000 0000000 cdef extern from "Python.h":
ctypedef void PyObject
############################################################################
# 7.5.4 Method Objects
############################################################################
# There are some useful functions that are useful for working with method objects.
# PyTypeObject PyMethod_Type
# This instance of PyTypeObject represents the Python method type. This is exposed to Python programs as types.MethodType.
bint PyMethod_Check(object o)
# Return true if o is a method object (has type
# PyMethod_Type). The parameter must not be NULL.
object PyMethod_New(object func, object self, object cls)
# Return value: New reference.
# Return a new method object, with func being any callable object;
# this is the function that will be called when the method is
# called. If this method should be bound to an instance, self
# should be the instance and class should be the class of self,
# otherwise self should be NULL and class should be the class
# which provides the unbound method..
PyObject* PyMethod_Class(object meth) except NULL
# Return value: Borrowed reference.
# Return the class object from which the method meth was created;
# if this was created from an instance, it will be the class of
# the instance.
PyObject* PyMethod_GET_CLASS(object meth)
# Return value: Borrowed reference.
# Macro version of PyMethod_Class() which avoids error checking.
PyObject* PyMethod_Function(object meth) except NULL
# Return value: Borrowed reference.
# Return the function object associated with the method meth.
PyObject* PyMethod_GET_FUNCTION(object meth)
# Return value: Borrowed reference.
# Macro version of PyMethod_Function() which avoids error checking.
PyObject* PyMethod_Self(object meth) except? NULL
# Return value: Borrowed reference.
# Return the instance associated with the method meth if it is bound, otherwise return NULL.
PyObject* PyMethod_GET_SELF(object meth)
# Return value: Borrowed reference.
# Macro version of PyMethod_Self() which avoids error checking.
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/module.pxd 0000664 0000000 0000000 00000020520 11446142532 0026443 0 ustar 00root root 0000000 0000000 from cpython.ref cimport PyObject
cdef extern from "Python.h":
ctypedef struct _inittab
#####################################################################
# 5.3 Importing Modules
#####################################################################
object PyImport_ImportModule(char *name)
# Return value: New reference.
# This is a simplified interface to PyImport_ImportModuleEx()
# below, leaving the globals and locals arguments set to
# NULL. When the name argument contains a dot (when it specifies a
# submodule of a package), the fromlist argument is set to the
# list ['*'] so that the return value is the named module rather
# than the top-level package containing it as would otherwise be
# the case. (Unfortunately, this has an additional side effect
# when name in fact specifies a subpackage instead of a submodule:
# the submodules specified in the package's __all__ variable are
# loaded.) Return a new reference to the imported module, or NULL
# with an exception set on failure.
object PyImport_ImportModuleEx(char *name, object globals, object locals, object fromlist)
# Return value: New reference.
# Import a module. This is best described by referring to the
# built-in Python function __import__(), as the standard
# __import__() function calls this function directly.
# The return value is a new reference to the imported module or
# top-level package, or NULL with an exception set on failure
# (before Python 2.4, the module may still be created in this
# case). Like for __import__(), the return value when a submodule
# of a package was requested is normally the top-level package,
# unless a non-empty fromlist was given. Changed in version 2.4:
# failing imports remove incomplete module objects.
object PyImport_Import(object name)
# Return value: New reference.
# This is a higher-level interface that calls the current ``import
# hook function''. It invokes the __import__() function from the
# __builtins__ of the current globals. This means that the import
# is done using whatever import hooks are installed in the current
# environment, e.g. by rexec or ihooks.
object PyImport_ReloadModule(object m)
# Return value: New reference.
# Reload a module. This is best described by referring to the
# built-in Python function reload(), as the standard reload()
# function calls this function directly. Return a new reference to
# the reloaded module, or NULL with an exception set on failure
# (the module still exists in this case).
PyObject* PyImport_AddModule(char *name) except NULL
# Return value: Borrowed reference.
# Return the module object corresponding to a module name. The
# name argument may be of the form package.module. First check the
# modules dictionary if there's one there, and if not, create a
# new one and insert it in the modules dictionary. Return NULL
# with an exception set on failure. Note: This function does not
# load or import the module; if the module wasn't already loaded,
# you will get an empty module object. Use PyImport_ImportModule()
# or one of its variants to import a module. Package structures
# implied by a dotted name for name are not created if not already
# present.
object PyImport_ExecCodeModule(char *name, object co)
# Return value: New reference.
# Given a module name (possibly of the form package.module) and a
# code object read from a Python bytecode file or obtained from
# the built-in function compile(), load the module. Return a new
# reference to the module object, or NULL with an exception set if
# an error occurred. Name is removed from sys.modules in error
# cases, and even if name was already in sys.modules on entry to
# PyImport_ExecCodeModule(). Leaving incompletely initialized
# modules in sys.modules is dangerous, as imports of such modules
# have no way to know that the module object is an unknown (and
# probably damaged with respect to the module author's intents)
# state.
# This function will reload the module if it was already
# imported. See PyImport_ReloadModule() for the intended way to
# reload a module.
# If name points to a dotted name of the form package.module, any
# package structures not already created will still not be
# created.
long PyImport_GetMagicNumber()
# Return the magic number for Python bytecode files (a.k.a. .pyc
# and .pyo files). The magic number should be present in the first
# four bytes of the bytecode file, in little-endian byte order.
PyObject* PyImport_GetModuleDict() except NULL
# Return value: Borrowed reference.
# Return the dictionary used for the module administration
# (a.k.a. sys.modules). Note that this is a per-interpreter
# variable.
int PyImport_ImportFrozenModule(char *name) except -1
# Load a frozen module named name. Return 1 for success, 0 if the
# module is not found, and -1 with an exception set if the
# initialization failed. To access the imported module on a
# successful load, use PyImport_ImportModule(). (Note the misnomer
# -- this function would reload the module if it was already
# imported.)
int PyImport_ExtendInittab(_inittab *newtab) except -1
# Add a collection of modules to the table of built-in
# modules. The newtab array must end with a sentinel entry which
# contains NULL for the name field; failure to provide the
# sentinel value can result in a memory fault. Returns 0 on
# success or -1 if insufficient memory could be allocated to
# extend the internal table. In the event of failure, no modules
# are added to the internal table. This should be called before
# Py_Initialize().
#####################################################################
# 7.5.5 Module Objects
#####################################################################
# PyTypeObject PyModule_Type
#
# This instance of PyTypeObject represents the Python module
# type. This is exposed to Python programs as types.ModuleType.
bint PyModule_Check(object p)
# Return true if p is a module object, or a subtype of a module
# object.
bint PyModule_CheckExact(object p)
# Return true if p is a module object, but not a subtype of PyModule_Type.
object PyModule_New(char *name)
# Return value: New reference.
# Return a new module object with the __name__ attribute set to
# name. Only the module's __doc__ and __name__ attributes are
# filled in; the caller is responsible for providing a __file__
# attribute.
PyObject* PyModule_GetDict(object module) except NULL
# Return value: Borrowed reference.
# Return the dictionary object that implements module's namespace;
# this object is the same as the __dict__ attribute of the module
# object. This function never fails. It is recommended extensions
# use other PyModule_*() and PyObject_*() functions rather than
# directly manipulate a module's __dict__.
char* PyModule_GetName(object module) except NULL
# Return module's __name__ value. If the module does not provide
# one, or if it is not a string, SystemError is raised and NULL is
# returned.
char* PyModule_GetFilename(object module) except NULL
# Return the name of the file from which module was loaded using
# module's __file__ attribute. If this is not defined, or if it is
# not a string, raise SystemError and return NULL.
int PyModule_AddObject(object module, char *name, object value) except -1
# Add an object to module as name. This is a convenience function
# which can be used from the module's initialization
# function. This steals a reference to value. Return -1 on error,
# 0 on success.
int PyModule_AddIntant(object module, char *name, long value) except -1
# Add an integer ant to module as name. This convenience
# function can be used from the module's initialization
# function. Return -1 on error, 0 on success.
int PyModule_AddStringant(object module, char *name, char *value) except -1
# Add a string constant to module as name. This convenience
# function can be used from the module's initialization
# function. The string value must be null-terminated. Return -1 on
# error, 0 on success.
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/number.pxd 0000664 0000000 0000000 00000026077 11446142532 0026463 0 ustar 00root root 0000000 0000000 from cpython.ref cimport PyObject
cdef extern from "Python.h":
#####################################################################
# 6.2 Number Protocol
#####################################################################
bint PyNumber_Check(object o)
# Returns 1 if the object o provides numeric protocols, and false
# otherwise. This function always succeeds.
object PyNumber_Add(object o1, object o2)
# Return value: New reference.
# Returns the result of adding o1 and o2, or NULL on failure. This
# is the equivalent of the Python expression "o1 + o2".
object PyNumber_Subtract(object o1, object o2)
# Return value: New reference.
# Returns the result of subtracting o2 from o1, or NULL on
# failure. This is the equivalent of the Python expression "o1 -
# o2".
object PyNumber_Multiply(object o1, object o2)
# Return value: New reference.
# Returns the result of multiplying o1 and o2, or NULL on
# failure. This is the equivalent of the Python expression "o1 *
# o2".
object PyNumber_Divide(object o1, object o2)
# Return value: New reference.
# Returns the result of dividing o1 by o2, or NULL on
# failure. This is the equivalent of the Python expression "o1 /
# o2".
object PyNumber_FloorDivide(object o1, object o2)
# Return value: New reference.
# Return the floor of o1 divided by o2, or NULL on failure. This
# is equivalent to the ``classic'' division of integers.
object PyNumber_TrueDivide(object o1, object o2)
# Return value: New reference.
# Return a reasonable approximation for the mathematical value of
# o1 divided by o2, or NULL on failure. The return value is
# ``approximate'' because binary floating point numbers are
# approximate; it is not possible to represent all real numbers in
# base two. This function can return a floating point value when
# passed two integers.
object PyNumber_Remainder(object o1, object o2)
# Return value: New reference.
# Returns the remainder of dividing o1 by o2, or NULL on
# failure. This is the equivalent of the Python expression "o1 %
# o2".
object PyNumber_Divmod(object o1, object o2)
# Return value: New reference.
# See the built-in function divmod(). Returns NULL on
# failure. This is the equivalent of the Python expression
# "divmod(o1, o2)".
object PyNumber_Power(object o1, object o2, object o3)
# Return value: New reference.
# See the built-in function pow(). Returns NULL on failure. This
# is the equivalent of the Python expression "pow(o1, o2, o3)",
# where o3 is optional. If o3 is to be ignored, pass Py_None in
# its place (passing NULL for o3 would cause an illegal memory
# access).
object PyNumber_Negative(object o)
# Return value: New reference.
# Returns the negation of o on success, or NULL on failure. This
# is the equivalent of the Python expression "-o".
object PyNumber_Positive(object o)
# Return value: New reference.
# Returns o on success, or NULL on failure. This is the equivalent
# of the Python expression "+o".
object PyNumber_Absolute(object o)
# Return value: New reference.
# Returns the absolute value of o, or NULL on failure. This is the
# equivalent of the Python expression "abs(o)".
object PyNumber_Invert(object o)
# Return value: New reference.
# Returns the bitwise negation of o on success, or NULL on
# failure. This is the equivalent of the Python expression "~o".
object PyNumber_Lshift(object o1, object o2)
# Return value: New reference.
# Returns the result of left shifting o1 by o2 on success, or NULL
# on failure. This is the equivalent of the Python expression "o1
# << o2".
object PyNumber_Rshift(object o1, object o2)
# Return value: New reference.
# Returns the result of right shifting o1 by o2 on success, or
# NULL on failure. This is the equivalent of the Python expression
# "o1 >> o2".
object PyNumber_And(object o1, object o2)
# Return value: New reference.
# Returns the ``bitwise and'' of o1 and o2 on success and NULL on
# failure. This is the equivalent of the Python expression "o1 &
# o2".
object PyNumber_Xor(object o1, object o2)
# Return value: New reference.
# Returns the ``bitwise exclusive or'' of o1 by o2 on success, or
# NULL on failure. This is the equivalent of the Python expression
# "o1 ^ o2".
object PyNumber_Or(object o1, object o2)
# Return value: New reference.
# Returns the ``bitwise or'' of o1 and o2 on success, or NULL on failure. This is the equivalent of the Python expression "o1 | o2".
object PyNumber_InPlaceAdd(object o1, object o2)
# Return value: New reference.
# Returns the result of adding o1 and o2, or NULL on failure. The
# operation is done in-place when o1 supports it. This is the
# equivalent of the Python statement "o1 += o2".
object PyNumber_InPlaceSubtract(object o1, object o2)
# Return value: New reference.
# Returns the result of subtracting o2 from o1, or NULL on
# failure. The operation is done in-place when o1 supports
# it. This is the equivalent of the Python statement "o1 -= o2".
object PyNumber_InPlaceMultiply(object o1, object o2)
# Return value: New reference.
# Returns the result of multiplying o1 and o2, or NULL on
# failure. The operation is done in-place when o1 supports
# it. This is the equivalent of the Python statement "o1 *= o2".
object PyNumber_InPlaceDivide(object o1, object o2)
# Return value: New reference.
# Returns the result of dividing o1 by o2, or NULL on failure. The
# operation is done in-place when o1 supports it. This is the
# equivalent of the Python statement "o1 /= o2".
object PyNumber_InPlaceFloorDivide(object o1, object o2)
# Return value: New reference.
# Returns the mathematical floor of dividing o1 by o2, or NULL on
# failure. The operation is done in-place when o1 supports
# it. This is the equivalent of the Python statement "o1 //=
# o2".
object PyNumber_InPlaceTrueDivide(object o1, object o2)
# Return value: New reference.
# Return a reasonable approximation for the mathematical value of
# o1 divided by o2, or NULL on failure. The return value is
# ``approximate'' because binary floating point numbers are
# approximate; it is not possible to represent all real numbers in
# base two. This function can return a floating point value when
# passed two integers. The operation is done in-place when o1
# supports it.
object PyNumber_InPlaceRemainder(object o1, object o2)
# Return value: New reference.
# Returns the remainder of dividing o1 by o2, or NULL on
# failure. The operation is done in-place when o1 supports
# it. This is the equivalent of the Python statement "o1 %= o2".
object PyNumber_InPlacePower(object o1, object o2, object o3)
# Return value: New reference.
# See the built-in function pow(). Returns NULL on failure. The
# operation is done in-place when o1 supports it. This is the
# equivalent of the Python statement "o1 **= o2" when o3 is
# Py_None, or an in-place variant of "pow(o1, o2, o3)"
# otherwise. If o3 is to be ignored, pass Py_None in its place
# (passing NULL for o3 would cause an illegal memory access).
object PyNumber_InPlaceLshift(object o1, object o2)
# Return value: New reference.
# Returns the result of left shifting o1 by o2 on success, or NULL
# on failure. The operation is done in-place when o1 supports
# it. This is the equivalent of the Python statement "o1 <<= o2".
object PyNumber_InPlaceRshift(object o1, object o2)
# Return value: New reference.
# Returns the result of right shifting o1 by o2 on success, or
# NULL on failure. The operation is done in-place when o1 supports
# it. This is the equivalent of the Python statement "o1 >>= o2".
object PyNumber_InPlaceAnd(object o1, object o2)
# Return value: New reference.
# Returns the ``bitwise and'' of o1 and o2 on success and NULL on
# failure. The operation is done in-place when o1 supports
# it. This is the equivalent of the Python statement "o1 &= o2".
object PyNumber_InPlaceXor(object o1, object o2)
# Return value: New reference.
# Returns the ``bitwise exclusive or'' of o1 by o2 on success, or
# NULL on failure. The operation is done in-place when o1 supports
# it. This is the equivalent of the Python statement "o1 ^= o2".
object PyNumber_InPlaceOr(object o1, object o2)
# Return value: New reference.
# Returns the ``bitwise or'' of o1 and o2 on success, or NULL on
# failure. The operation is done in-place when o1 supports
# it. This is the equivalent of the Python statement "o1 |= o2".
int PyNumber_Coerce(PyObject **p1, PyObject **p2) except -1
# This function takes the addresses of two variables of type
# PyObject*. If the objects pointed to by *p1 and *p2 have the
# same type, increment their reference count and return 0
# (success). If the objects can be converted to a common numeric
# type, replace *p1 and *p2 by their converted value (with 'new'
# reference counts), and return 0. If no conversion is possible,
# or if some other error occurs, return -1 (failure) and don't
# increment the reference counts. The call PyNumber_Coerce(&o1,
# &o2) is equivalent to the Python statement "o1, o2 = coerce(o1,
# o2)".
object PyNumber_Int(object o)
# Return value: New reference.
# Returns the o converted to an integer object on success, or NULL
# on failure. If the argument is outside the integer range a long
# object will be returned instead. This is the equivalent of the
# Python expression "int(o)".
object PyNumber_Long(object o)
# Return value: New reference.
# Returns the o converted to a long integer object on success, or
# NULL on failure. This is the equivalent of the Python expression
# "long(o)".
object PyNumber_Float(object o)
# Return value: New reference.
# Returns the o converted to a float object on success, or NULL on
# failure. This is the equivalent of the Python expression
# "float(o)".
object PyNumber_Index(object o)
# Returns the o converted to a Python int or long on success or
# NULL with a TypeError exception raised on failure.
Py_ssize_t PyNumber_AsSsize_t(object o, object exc) except? -1
# Returns o converted to a Py_ssize_t value if o can be
# interpreted as an integer. If o can be converted to a Python int
# or long but the attempt to convert to a Py_ssize_t value would
# raise an OverflowError, then the exc argument is the type of
# exception that will be raised (usually IndexError or
# OverflowError). If exc is NULL, then the exception is cleared
# and the value is clipped to PY_SSIZE_T_MIN for a negative
# integer or PY_SSIZE_T_MAX for a positive integer.
bint PyIndex_Check(object o)
# Returns True if o is an index integer (has the nb_index slot of
# the tp_as_number structure filled in).
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/object.pxd 0000664 0000000 0000000 00000034246 11446142532 0026436 0 ustar 00root root 0000000 0000000 from cpython.ref cimport PyObject, PyTypeObject
from libc.stdio cimport FILE
cdef extern from "Python.h":
#####################################################################
# 6.1 Object Protocol
#####################################################################
int PyObject_Print(object o, FILE *fp, int flags) except -1
# Print an object o, on file fp. Returns -1 on error. The flags
# argument is used to enable certain printing options. The only
# option currently supported is Py_PRINT_RAW; if given, the str()
# of the object is written instead of the repr().
bint PyObject_HasAttrString(object o, char *attr_name)
# Returns 1 if o has the attribute attr_name, and 0
# otherwise. This is equivalent to the Python expression
# "hasattr(o, attr_name)". This function always succeeds.
object PyObject_GetAttrString(object o, char *attr_name)
# Return value: New reference. Retrieve an attribute named
# attr_name from object o. Returns the attribute value on success,
# or NULL on failure. This is the equivalent of the Python
# expression "o.attr_name".
bint PyObject_HasAttr(object o, object attr_name)
# Returns 1 if o has the attribute attr_name, and 0
# otherwise. This is equivalent to the Python expression
# "hasattr(o, attr_name)". This function always succeeds.
object PyObject_GetAttr(object o, object attr_name)
# Return value: New reference. Retrieve an attribute named
# attr_name from object o. Returns the attribute value on success,
# or NULL on failure. This is the equivalent of the Python
# expression "o.attr_name".
int PyObject_SetAttrString(object o, char *attr_name, object v) except -1
# Set the value of the attribute named attr_name, for object o, to
# the value v. Returns -1 on failure. This is the equivalent of
# the Python statement "o.attr_name = v".
int PyObject_SetAttr(object o, object attr_name, object v) except -1
# Set the value of the attribute named attr_name, for object o, to
# the value v. Returns -1 on failure. This is the equivalent of
# the Python statement "o.attr_name = v".
int PyObject_DelAttrString(object o, char *attr_name) except -1
# Delete attribute named attr_name, for object o. Returns -1 on
# failure. This is the equivalent of the Python statement: "del
# o.attr_name".
int PyObject_DelAttr(object o, object attr_name) except -1
# Delete attribute named attr_name, for object o. Returns -1 on
# failure. This is the equivalent of the Python statement "del
# o.attr_name".
int Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, Py_GE
object PyObject_RichCompare(object o1, object o2, int opid)
# Return value: New reference.
# Compare the values of o1 and o2 using the operation specified by
# opid, which must be one of Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, or
# Py_GE, corresponding to <, <=, ==, !=, >, or >=
# respectively. This is the equivalent of the Python expression
# "o1 op o2", where op is the operator corresponding to
# opid. Returns the value of the comparison on success, or NULL on
# failure.
bint PyObject_RichCompareBool(object o1, object o2, int opid) except -1
# Compare the values of o1 and o2 using the operation specified by
# opid, which must be one of Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, or
# Py_GE, corresponding to <, <=, ==, !=, >, or >=
# respectively. Returns -1 on error, 0 if the result is false, 1
# otherwise. This is the equivalent of the Python expression "o1
# op o2", where op is the operator corresponding to opid.
int PyObject_Cmp(object o1, object o2, int *result) except -1
# Compare the values of o1 and o2 using a routine provided by o1,
# if one exists, otherwise with a routine provided by o2. The
# result of the comparison is returned in result. Returns -1 on
# failure. This is the equivalent of the Python statement "result
# = cmp(o1, o2)".
int PyObject_Compare(object o1, object o2) except *
# Compare the values of o1 and o2 using a routine provided by o1,
# if one exists, otherwise with a routine provided by o2. Returns
# the result of the comparison on success. On error, the value
# returned is undefined; use PyErr_Occurred() to detect an
# error. This is equivalent to the Python expression "cmp(o1,
# o2)".
object PyObject_Repr(object o)
# Return value: New reference.
# Compute a string representation of object o. Returns the string
# representation on success, NULL on failure. This is the
# equivalent of the Python expression "repr(o)". Called by the
# repr() built-in function and by reverse quotes.
object PyObject_Str(object o)
# Return value: New reference.
# Compute a string representation of object o. Returns the string
# representation on success, NULL on failure. This is the
# equivalent of the Python expression "str(o)". Called by the
# str() built-in function and by the print statement.
object PyObject_Unicode(object o)
# Return value: New reference.
# Compute a Unicode string representation of object o. Returns the
# Unicode string representation on success, NULL on failure. This
# is the equivalent of the Python expression "unicode(o)". Called
# by the unicode() built-in function.
bint PyObject_IsInstance(object inst, object cls) except -1
# Returns 1 if inst is an instance of the class cls or a subclass
# of cls, or 0 if not. On error, returns -1 and sets an
# exception. If cls is a type object rather than a class object,
# PyObject_IsInstance() returns 1 if inst is of type cls. If cls
# is a tuple, the check will be done against every entry in
# cls. The result will be 1 when at least one of the checks
# returns 1, otherwise it will be 0. If inst is not a class
# instance and cls is neither a type object, nor a class object,
# nor a tuple, inst must have a __class__ attribute -- the class
# relationship of the value of that attribute with cls will be
# used to determine the result of this function.
# Subclass determination is done in a fairly straightforward way,
# but includes a wrinkle that implementors of extensions to the
# class system may want to be aware of. If A and B are class
# objects, B is a subclass of A if it inherits from A either
# directly or indirectly. If either is not a class object, a more
# general mechanism is used to determine the class relationship of
# the two objects. When testing if B is a subclass of A, if A is
# B, PyObject_IsSubclass() returns true. If A and B are different
# objects, B's __bases__ attribute is searched in a depth-first
# fashion for A -- the presence of the __bases__ attribute is
# considered sufficient for this determination.
bint PyObject_IsSubclass(object derived, object cls) except -1
# Returns 1 if the class derived is identical to or derived from
# the class cls, otherwise returns 0. In case of an error, returns
# -1. If cls is a tuple, the check will be done against every
# entry in cls. The result will be 1 when at least one of the
# checks returns 1, otherwise it will be 0. If either derived or
# cls is not an actual class object (or tuple), this function uses
# the generic algorithm described above. New in version
# 2.1. Changed in version 2.3: Older versions of Python did not
# support a tuple as the second argument.
bint PyCallable_Check(object o)
# Determine if the object o is callable. Return 1 if the object is
# callable and 0 otherwise. This function always succeeds.
object PyObject_Call(object callable_object, object args, object kw)
# Return value: New reference.
# Call a callable Python object callable_object, with arguments
# given by the tuple args, and named arguments given by the
# dictionary kw. If no named arguments are needed, kw may be
# NULL. args must not be NULL, use an empty tuple if no arguments
# are needed. Returns the result of the call on success, or NULL
# on failure. This is the equivalent of the Python expression
# "apply(callable_object, args, kw)" or "callable_object(*args,
# **kw)".
object PyObject_CallObject(object callable_object, object args)
# Return value: New reference.
# Call a callable Python object callable_object, with arguments
# given by the tuple args. If no arguments are needed, then args
# may be NULL. Returns the result of the call on success, or NULL
# on failure. This is the equivalent of the Python expression
# "apply(callable_object, args)" or "callable_object(*args)".
object PyObject_CallFunction(object callable, char *format, ...)
# Return value: New reference.
# Call a callable Python object callable, with a variable number
# of C arguments. The C arguments are described using a
# Py_BuildValue() style format string. The format may be NULL,
# indicating that no arguments are provided. Returns the result of
# the call on success, or NULL on failure. This is the equivalent
# of the Python expression "apply(callable, args)" or
# "callable(*args)". Note that if you only pass object args,
# PyObject_CallFunctionObjArgs is a faster alternative.
object PyObject_CallMethod(object o, char *method, char *format, ...)
# Return value: New reference.
# Call the method named method of object o with a variable number
# of C arguments. The C arguments are described by a
# Py_BuildValue() format string that should produce a tuple. The
# format may be NULL, indicating that no arguments are
# provided. Returns the result of the call on success, or NULL on
# failure. This is the equivalent of the Python expression
# "o.method(args)". Note that if you only pass object args,
# PyObject_CallMethodObjArgs is a faster alternative.
#object PyObject_CallFunctionObjArgs(object callable, ..., NULL)
object PyObject_CallFunctionObjArgs(object callable, ...)
# Return value: New reference.
# Call a callable Python object callable, with a variable number
# of PyObject* arguments. The arguments are provided as a variable
# number of parameters followed by NULL. Returns the result of the
# call on success, or NULL on failure.
#PyObject* PyObject_CallMethodObjArgs(object o, object name, ..., NULL)
object PyObject_CallMethodObjArgs(object o, object name, ...)
# Return value: New reference.
# Calls a method of the object o, where the name of the method is
# given as a Python string object in name. It is called with a
# variable number of PyObject* arguments. The arguments are
# provided as a variable number of parameters followed by
# NULL. Returns the result of the call on success, or NULL on
# failure.
long PyObject_Hash(object o) except? -1
# Compute and return the hash value of an object o. On failure,
# return -1. This is the equivalent of the Python expression
# "hash(o)".
bint PyObject_IsTrue(object o) except -1
# Returns 1 if the object o is considered to be true, and 0
# otherwise. This is equivalent to the Python expression "not not
# o". On failure, return -1.
bint PyObject_Not(object o) except -1
# Returns 0 if the object o is considered to be true, and 1
# otherwise. This is equivalent to the Python expression "not
# o". On failure, return -1.
object PyObject_Type(object o)
# Return value: New reference.
# When o is non-NULL, returns a type object corresponding to the
# object type of object o. On failure, raises SystemError and
# returns NULL. This is equivalent to the Python expression
# type(o). This function increments the reference count of the
# return value. There's really no reason to use this function
# instead of the common expression o->ob_type, which returns a
# pointer of type PyTypeObject*, except when the incremented
# reference count is needed.
bint PyObject_TypeCheck(object o, PyTypeObject *type)
# Return true if the object o is of type type or a subtype of
# type. Both parameters must be non-NULL.
Py_ssize_t PyObject_Length(object o) except -1
Py_ssize_t PyObject_Size(object o) except -1
# Return the length of object o. If the object o provides either
# the sequence and mapping protocols, the sequence length is
# returned. On error, -1 is returned. This is the equivalent to
# the Python expression "len(o)".
object PyObject_GetItem(object o, object key)
# Return value: New reference.
# Return element of o corresponding to the object key or NULL on
# failure. This is the equivalent of the Python expression
# "o[key]".
int PyObject_SetItem(object o, object key, object v) except -1
# Map the object key to the value v. Returns -1 on failure. This
# is the equivalent of the Python statement "o[key] = v".
int PyObject_DelItem(object o, object key) except -1
# Delete the mapping for key from o. Returns -1 on failure. This
# is the equivalent of the Python statement "del o[key]".
int PyObject_AsFileDescriptor(object o) except -1
# Derives a file-descriptor from a Python object. If the object is
# an integer or long integer, its value is returned. If not, the
# object's fileno() method is called if it exists; the method must
# return an integer or long integer, which is returned as the file
# descriptor value. Returns -1 on failure.
object PyObject_Dir(object o)
# Return value: New reference.
# This is equivalent to the Python expression "dir(o)", returning
# a (possibly empty) list of strings appropriate for the object
# argument, or NULL if there was an error. If the argument is
# NULL, this is like the Python "dir()", returning the names of
# the current locals; in this case, if no execution frame is
# active then NULL is returned but PyErr_Occurred() will return
# false.
object PyObject_GetIter(object o)
# Return value: New reference.
# This is equivalent to the Python expression "iter(o)". It
# returns a new iterator for the object argument, or the object
# itself if the object is already an iterator. Raises TypeError
# and returns NULL if the object cannot be iterated.
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/oldbuffer.pxd 0000664 0000000 0000000 00000005544 11446142532 0027137 0 ustar 00root root 0000000 0000000 # Legacy Python 2 buffer interface.
#
# These functions are no longer available in Python 3, use the new
# buffer interface instead.
cdef extern from "Python.h":
cdef enum _:
Py_END_OF_BUFFER
# This constant may be passed as the size parameter to
# PyBuffer_FromObject() or PyBuffer_FromReadWriteObject(). It
# indicates that the new PyBufferObject should refer to base object
# from the specified offset to the end of its exported
# buffer. Using this enables the caller to avoid querying the base
# object for its length.
bint PyBuffer_Check(object p)
# Return true if the argument has type PyBuffer_Type.
object PyBuffer_FromObject(object base, Py_ssize_t offset, Py_ssize_t size)
# Return value: New reference.
#
# Return a new read-only buffer object. This raises TypeError if
# base doesn't support the read-only buffer protocol or doesn't
# provide exactly one buffer segment, or it raises ValueError if
# offset is less than zero. The buffer will hold a reference to the
# base object, and the buffer's contents will refer to the base
# object's buffer interface, starting as position offset and
# extending for size bytes. If size is Py_END_OF_BUFFER, then the
# new buffer's contents extend to the length of the base object's
# exported buffer data.
object PyBuffer_FromReadWriteObject(object base, Py_ssize_t offset, Py_ssize_t size)
# Return value: New reference.
#
# Return a new writable buffer object. Parameters and exceptions
# are similar to those for PyBuffer_FromObject(). If the base
# object does not export the writeable buffer protocol, then
# TypeError is raised.
object PyBuffer_FromMemory(void *ptr, Py_ssize_t size)
# Return value: New reference.
#
# Return a new read-only buffer object that reads from a specified
# location in memory, with a specified size. The caller is
# responsible for ensuring that the memory buffer, passed in as
# ptr, is not deallocated while the returned buffer object
# exists. Raises ValueError if size is less than zero. Note that
# Py_END_OF_BUFFER may not be passed for the size parameter;
# ValueError will be raised in that case.
object PyBuffer_FromReadWriteMemory(void *ptr, Py_ssize_t size)
# Return value: New reference.
#
# Similar to PyBuffer_FromMemory(), but the returned buffer is
# writable.
object PyBuffer_New(Py_ssize_t size)
# Return value: New reference.
#
# Return a new writable buffer object that maintains its own memory
# buffer of size bytes. ValueError is returned if size is not zero
# or positive. Note that the memory buffer (as returned by
# PyObject_AsWriteBuffer()) is not specifically aligned.
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/pycapsule.pxd 0000664 0000000 0000000 00000013174 11446142532 0027172 0 ustar 00root root 0000000 0000000 from cpython.ref cimport PyObject
# available since Python 3.1!
# note all char* in the below functions are actually const char*
cdef extern from "Python.h":
ctypedef struct PyCapsule_Type
# This subtype of PyObject represents an opaque value, useful for
# C extension modules who need to pass an opaque value (as a void*
# pointer) through Python code to other C code. It is often used
# to make a C function pointer defined in one module available to
# other modules, so the regular import mechanism can be used to
# access C APIs defined in dynamically loaded modules.
ctypedef void (*PyCapsule_Destructor)(object o)
# The type of a destructor callback for a capsule.
#
# See PyCapsule_New() for the semantics of PyCapsule_Destructor
# callbacks.
bint PyCapsule_CheckExact(object o)
# Return true if its argument is a PyCapsule.
object PyCapsule_New(void *pointer, char *name,
PyCapsule_Destructor destructor)
# Return value: New reference.
#
# Create a PyCapsule encapsulating the pointer. The pointer
# argument may not be NULL.
#
# On failure, set an exception and return NULL.
#
# The name string may either be NULL or a pointer to a valid C
# string. If non-NULL, this string must outlive the
# capsule. (Though it is permitted to free it inside the
# destructor.)
#
# If the destructor argument is not NULL, it will be called with
# the capsule as its argument when it is destroyed.
#
# If this capsule will be stored as an attribute of a module, the
# name should be specified as modulename.attributename. This will
# enable other modules to import the capsule using
# PyCapsule_Import().
void* PyCapsule_GetPointer(object capsule, char *name) except? NULL
# Retrieve the pointer stored in the capsule. On failure, set an
# exception and return NULL.
#
# The name parameter must compare exactly to the name stored in
# the capsule. If the name stored in the capsule is NULL, the name
# passed in must also be NULL. Python uses the C function strcmp()
# to compare capsule names.
PyCapsule_Destructor PyCapsule_GetDestructor(object capsule) except? NULL
# Return the current destructor stored in the capsule. On failure,
# set an exception and return NULL.
#
# It is legal for a capsule to have a NULL destructor. This makes
# a NULL return code somewhat ambiguous; use PyCapsule_IsValid()
# or PyErr_Occurred() to disambiguate.
char* PyCapsule_GetName(object capsule) except? NULL
# Return the current name stored in the capsule. On failure, set
# an exception and return NULL.
#
# It is legal for a capsule to have a NULL name. This makes a NULL
# return code somewhat ambiguous; use PyCapsule_IsValid() or
# PyErr_Occurred() to disambiguate.
void* PyCapsule_GetContext(object capsule) except? NULL
# Return the current context stored in the capsule. On failure,
# set an exception and return NULL.
#
# It is legal for a capsule to have a NULL context. This makes a
# NULL return code somewhat ambiguous; use PyCapsule_IsValid() or
# PyErr_Occurred() to disambiguate.
bint PyCapsule_IsValid(object capsule, char *name)
# Determines whether or not capsule is a valid capsule. A valid
# capsule is non-NULL, passes PyCapsule_CheckExact(), has a
# non-NULL pointer stored in it, and its internal name matches the
# name parameter. (See PyCapsule_GetPointer() for information on
# how capsule names are compared.)
#
# In other words, if PyCapsule_IsValid() returns a true value,
# calls to any of the accessors (any function starting with
# PyCapsule_Get()) are guaranteed to succeed.
#
# Return a nonzero value if the object is valid and matches the
# name passed in. Return 0 otherwise. This function will not fail.
int PyCapsule_SetPointer(object capsule, void *pointer) except -1
# Set the void pointer inside capsule to pointer. The pointer may
# not be NULL.
#
# Return 0 on success. Return nonzero and set an exception on
# failure.
int PyCapsule_SetDestructor(object capsule, PyCapsule_Destructor destructor) except -1
# Set the destructor inside capsule to destructor.
#
# Return 0 on success. Return nonzero and set an exception on
# failure.
int PyCapsule_SetName(object capsule, char *name) except -1
# Set the name inside capsule to name. If non-NULL, the name must
# outlive the capsule. If the previous name stored in the capsule
# was not NULL, no attempt is made to free it.
#
# Return 0 on success. Return nonzero and set an exception on
# failure.
int PyCapsule_SetContext(object capsule, void *context) except -1
# Set the context pointer inside capsule to context. Return 0 on
# success. Return nonzero and set an exception on failure.
void* PyCapsule_Import(char *name, int no_block) except? NULL
# Import a pointer to a C object from a capsule attribute in a
# module. The name parameter should specify the full name to the
# attribute, as in module.attribute. The name stored in the
# capsule must match this string exactly. If no_block is true,
# import the module without blocking (using
# PyImport_ImportModuleNoBlock()). If no_block is false, import
# the module conventionally (using PyImport_ImportModule()).
#
# Return the capsule’s internal pointer on success. On failure,
# set an exception and return NULL. However, if PyCapsule_Import()
# failed to import the module, and no_block was true, no exception
# is set.
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/pythread.pxd 0000664 0000000 0000000 00000001673 11446142532 0027006 0 ustar 00root root 0000000 0000000
cdef extern from "pythread.h":
ctypedef void *PyThread_type_lock
ctypedef void *PyThread_type_sema
void PyThread_init_thread()
long PyThread_start_new_thread(void (*)(void *), void *)
void PyThread_exit_thread()
long PyThread_get_thread_ident()
PyThread_type_lock PyThread_allocate_lock()
void PyThread_free_lock(PyThread_type_lock)
int PyThread_acquire_lock(PyThread_type_lock, int mode) nogil
void PyThread_release_lock(PyThread_type_lock) nogil
enum: # 'mode' in PyThread_acquire_lock
WAIT_LOCK # 1
NOWAIT_LOCK # 0
size_t PyThread_get_stacksize()
int PyThread_set_stacksize(size_t)
# Thread Local Storage (TLS) API
int PyThread_create_key()
void PyThread_delete_key(int)
int PyThread_set_key_value(int, void *)
void * PyThread_get_key_value(int)
void PyThread_delete_key_value(int key)
# Cleanup after a fork
void PyThread_ReInitTLS()
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/ref.pxd 0000664 0000000 0000000 00000005044 11446142532 0025736 0 ustar 00root root 0000000 0000000 cdef extern from "Python.h":
ctypedef struct PyTypeObject
ctypedef struct PyObject:
Py_ssize_t ob_refcnt
PyTypeObject *ob_type
#####################################################################
# 3. Reference Counts
#####################################################################
# The macros in this section are used for managing reference counts of Python objects.
void Py_INCREF(object o)
# Increment the reference count for object o. The object must not
# be NULL; if you aren't sure that it isn't NULL, use
# Py_XINCREF().
void Py_XINCREF(PyObject* o)
# Increment the reference count for object o. The object may be NULL, in which case the macro has no effect.
void Py_DECREF(object o)
# Decrement the reference count for object o. The object must not
# be NULL; if you aren't sure that it isn't NULL, use
# Py_XDECREF(). If the reference count reaches zero, the object's
# type's deallocation function (which must not be NULL) is
# invoked.
# Warning: The deallocation function can cause arbitrary Python
# code to be invoked (e.g. when a class instance with a __del__()
# method is deallocated). While exceptions in such code are not
# propagated, the executed code has free access to all Python
# global variables. This means that any object that is reachable
# from a global variable should be in a consistent state before
# Py_DECREF() is invoked. For example, code to delete an object
# from a list should copy a reference to the deleted object in a
# temporary variable, update the list data structure, and then
# call Py_DECREF() for the temporary variable.
void Py_XDECREF(PyObject* o)
# Decrement the reference count for object o. The object may be
# NULL, in which case the macro has no effect; otherwise the
# effect is the same as for Py_DECREF(), and the same warning
# applies.
void Py_CLEAR(PyObject* o)
# Decrement the reference count for object o. The object may be
# NULL, in which case the macro has no effect; otherwise the
# effect is the same as for Py_DECREF(), except that the argument
# is also set to NULL. The warning for Py_DECREF() does not apply
# with respect to the object passed because the macro carefully
# uses a temporary variable and sets the argument to NULL before
# decrementing its reference count.
# It is a good idea to use this macro whenever decrementing the
# value of a variable that might be traversed during garbage
# collection.
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/sequence.pxd 0000664 0000000 0000000 00000013560 11446142532 0026774 0 ustar 00root root 0000000 0000000 from cpython.ref cimport PyObject
cdef extern from "Python.h":
############################################################################
# 6.3 Sequence Protocol
############################################################################
bint PySequence_Check(object o)
# Return 1 if the object provides sequence protocol, and 0
# otherwise. This function always succeeds.
Py_ssize_t PySequence_Size(object o) except -1
# Returns the number of objects in sequence o on success, and -1
# on failure. For objects that do not provide sequence protocol,
# this is equivalent to the Python expression "len(o)".
Py_ssize_t PySequence_Length(object o) except -1
# Alternate name for PySequence_Size().
object PySequence_Concat(object o1, object o2)
# Return value: New reference.
# Return the concatenation of o1 and o2 on success, and NULL on
# failure. This is the equivalent of the Python expression "o1 +
# o2".
object PySequence_Repeat(object o, Py_ssize_t count)
# Return value: New reference.
# Return the result of repeating sequence object o count times, or
# NULL on failure. This is the equivalent of the Python expression
# "o * count".
object PySequence_InPlaceConcat(object o1, object o2)
# Return value: New reference.
# Return the concatenation of o1 and o2 on success, and NULL on
# failure. The operation is done in-place when o1 supports
# it. This is the equivalent of the Python expression "o1 += o2".
object PySequence_InPlaceRepeat(object o, Py_ssize_t count)
# Return value: New reference.
# Return the result of repeating sequence object o count times, or
# NULL on failure. The operation is done in-place when o supports
# it. This is the equivalent of the Python expression "o *=
# count".
object PySequence_GetItem(object o, Py_ssize_t i)
# Return value: New reference.
# Return the ith element of o, or NULL on failure. This is the
# equivalent of the Python expression "o[i]".
object PySequence_GetSlice(object o, Py_ssize_t i1, Py_ssize_t i2)
# Return value: New reference.
# Return the slice of sequence object o between i1 and i2, or NULL
# on failure. This is the equivalent of the Python expression
# "o[i1:i2]".
int PySequence_SetItem(object o, Py_ssize_t i, object v) except -1
# Assign object v to the ith element of o. Returns -1 on
# failure. This is the equivalent of the Python statement "o[i] =
# v". This function does not steal a reference to v.
int PySequence_DelItem(object o, Py_ssize_t i) except -1
# Delete the ith element of object o. Returns -1 on failure. This
# is the equivalent of the Python statement "del o[i]".
int PySequence_SetSlice(object o, Py_ssize_t i1, Py_ssize_t i2, object v) except -1
# Assign the sequence object v to the slice in sequence object o
# from i1 to i2. This is the equivalent of the Python statement
# "o[i1:i2] = v".
int PySequence_DelSlice(object o, Py_ssize_t i1, Py_ssize_t i2) except -1
# Delete the slice in sequence object o from i1 to i2. Returns -1
# on failure. This is the equivalent of the Python statement "del
# o[i1:i2]".
int PySequence_Count(object o, object value) except -1
# Return the number of occurrences of value in o, that is, return
# the number of keys for which o[key] == value. On failure, return
# -1. This is equivalent to the Python expression
# "o.count(value)".
int PySequence_Contains(object o, object value) except -1
# Determine if o contains value. If an item in o is equal to
# value, return 1, otherwise return 0. On error, return -1. This
# is equivalent to the Python expression "value in o".
int PySequence_Index(object o, object value) except -1
# Return the first index i for which o[i] == value. On error,
# return -1. This is equivalent to the Python expression
# "o.index(value)".
object PySequence_List(object o)
# Return value: New reference.
# Return a list object with the same contents as the arbitrary
# sequence o. The returned list is guaranteed to be new.
object PySequence_Tuple(object o)
# Return value: New reference.
# Return a tuple object with the same contents as the arbitrary
# sequence o or NULL on failure. If o is a tuple, a new reference
# will be returned, otherwise a tuple will be constructed with the
# appropriate contents. This is equivalent to the Python
# expression "tuple(o)".
object PySequence_Fast(object o, char *m)
# Return value: New reference.
# Returns the sequence o as a tuple, unless it is already a tuple
# or list, in which case o is returned. Use
# PySequence_Fast_GET_ITEM() to access the members of the
# result. Returns NULL on failure. If the object is not a
# sequence, raises TypeError with m as the message text.
PyObject* PySequence_Fast_GET_ITEM(object o, Py_ssize_t i)
# Return value: Borrowed reference.
# Return the ith element of o, assuming that o was returned by
# PySequence_Fast(), o is not NULL, and that i is within bounds.
PyObject** PySequence_Fast_ITEMS(object o)
# Return the underlying array of PyObject pointers. Assumes that o
# was returned by PySequence_Fast() and o is not NULL.
object PySequence_ITEM(object o, Py_ssize_t i)
# Return value: New reference.
# Return the ith element of o or NULL on failure. Macro form of
# PySequence_GetItem() but without checking that
# PySequence_Check(o) is true and without adjustment for negative
# indices.
int PySequence_Fast_GET_SIZE(object o)
# Returns the length of o, assuming that o was returned by
# PySequence_Fast() and that o is not NULL. The size can also be
# gotten by calling PySequence_Size() on o, but
# PySequence_Fast_GET_SIZE() is faster because it can assume o is
# a list or tuple.
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/set.pxd 0000664 0000000 0000000 00000012052 11446142532 0025752 0 ustar 00root root 0000000 0000000 cdef extern from "Python.h":
############################################################################
# 7.5.14 Set Objects
############################################################################
# This section details the public API for set and frozenset
# objects. Any functionality not listed below is best accessed
# using the either the abstract object protocol (including
# PyObject_CallMethod(), PyObject_RichCompareBool(),
# PyObject_Hash(), PyObject_Repr(), PyObject_IsTrue(),
# PyObject_Print(), and PyObject_GetIter()) or the abstract number
# protocol (including PyNumber_Add(), PyNumber_Subtract(),
# PyNumber_Or(), PyNumber_Xor(), PyNumber_InPlaceAdd(),
# PyNumber_InPlaceSubtract(), PyNumber_InPlaceOr(), and
# PyNumber_InPlaceXor()).
# PySetObject
# This subtype of PyObject is used to hold the internal data for
# both set and frozenset objects. It is like a PyDictObject in
# that it is a fixed size for small sets (much like tuple storage)
# and will point to a separate, variable sized block of memory for
# medium and large sized sets (much like list storage). None of
# the fields of this structure should be considered public and are
# subject to change. All access should be done through the
# documented API rather than by manipulating the values in the
# structure.
# PyTypeObject PySet_Type
# This is an instance of PyTypeObject representing the Python set type.
# PyTypeObject PyFrozenSet_Type
# This is an instance of PyTypeObject representing the Python frozenset type.
# The following type check macros work on pointers to any Python
# object. Likewise, the constructor functions work with any
# iterable Python object.
bint PyAnySet_Check(object p)
# Return true if p is a set object, a frozenset object, or an
# instance of a subtype.
bint PyAnySet_CheckExact(object p)
# Return true if p is a set object or a frozenset object but not
# an instance of a subtype.
bint PyFrozenSet_CheckExact(object p)
# Return true if p is a frozenset object but not an instance of a subtype.
object PySet_New(object iterable)
# Return value: New reference.
# Return a new set containing objects returned by the
# iterable. The iterable may be NULL to create a new empty
# set. Return the new set on success or NULL on failure. Raise
# TypeError if iterable is not actually iterable. The constructor
# is also useful for copying a set (c=set(s)).
object PyFrozenSet_New(object iterable)
# Return value: New reference.
# Return a new frozenset containing objects returned by the
# iterable. The iterable may be NULL to create a new empty
# frozenset. Return the new set on success or NULL on
# failure. Raise TypeError if iterable is not actually iterable.
# The following functions and macros are available for instances
# of set or frozenset or instances of their subtypes.
int PySet_Size(object anyset) except -1
# Return the length of a set or frozenset object. Equivalent to
# "len(anyset)". Raises a PyExc_SystemError if anyset is not a
# set, frozenset, or an instance of a subtype.
int PySet_GET_SIZE(object anyset)
# Macro form of PySet_Size() without error checking.
bint PySet_Contains(object anyset, object key) except -1
# Return 1 if found, 0 if not found, and -1 if an error is
# encountered. Unlike the Python __contains__() method, this
# function does not automatically convert unhashable sets into
# temporary frozensets. Raise a TypeError if the key is
# unhashable. Raise PyExc_SystemError if anyset is not a set,
# frozenset, or an instance of a subtype.
# The following functions are available for instances of set or
# its subtypes but not for instances of frozenset or its subtypes.
int PySet_Add(object set, object key) except -1
# Add key to a set instance. Does not apply to frozenset
# instances. Return 0 on success or -1 on failure. Raise a
# TypeError if the key is unhashable. Raise a MemoryError if there
# is no room to grow. Raise a SystemError if set is an not an
# instance of set or its subtype.
bint PySet_Discard(object set, object key) except -1
# Return 1 if found and removed, 0 if not found (no action taken),
# and -1 if an error is encountered. Does not raise KeyError for
# missing keys. Raise a TypeError if the key is unhashable. Unlike
# the Python discard() method, this function does not
# automatically convert unhashable sets into temporary
# frozensets. Raise PyExc_SystemError if set is an not an instance
# of set or its subtype.
object PySet_Pop(object set)
# Return value: New reference.
# Return a new reference to an arbitrary object in the set, and
# removes the object from the set. Return NULL on failure. Raise
# KeyError if the set is empty. Raise a SystemError if set is an
# not an instance of set or its subtype.
int PySet_Clear(object set)
# Empty an existing set of all elements.
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/string.pxd 0000664 0000000 0000000 00000023347 11446142532 0026476 0 ustar 00root root 0000000 0000000 from cpython.ref cimport PyObject
cdef extern from "Python.h":
ctypedef struct va_list
############################################################################
# 7.3.1 String Objects
############################################################################
# These functions raise TypeError when expecting a string
# parameter and are called with a non-string parameter.
# PyStringObject
# This subtype of PyObject represents a Python string object.
# PyTypeObject PyString_Type
# This instance of PyTypeObject represents the Python string type;
# it is the same object as str and types.StringType in the Python
# layer.
bint PyString_Check(object o)
# Return true if the object o is a string object or an instance of
# a subtype of the string type.
bint PyString_CheckExact(object o)
# Return true if the object o is a string object, but not an instance of a subtype of the string type.
object PyString_FromString(char *v)
# Return value: New reference.
# Return a new string object with the value v on success, and NULL
# on failure. The parameter v must not be NULL; it will not be
# checked.
object PyString_FromStringAndSize(char *v, Py_ssize_t len)
# Return value: New reference.
# Return a new string object with the value v and length len on
# success, and NULL on failure. If v is NULL, the contents of the
# string are uninitialized.
object PyString_FromFormat(char *format, ...)
# Return value: New reference.
# Take a C printf()-style format string and a variable number of
# arguments, calculate the size of the resulting Python string and
# return a string with the values formatted into it. The variable
# arguments must be C types and must correspond exactly to the
# format characters in the format string. The following format
# characters are allowed:
# Format Characters Type Comment
# %% n/a The literal % character.
# %c int A single character, represented as an C int.
# %d int Exactly equivalent to printf("%d").
# %u unsigned int Exactly equivalent to printf("%u").
# %ld long Exactly equivalent to printf("%ld").
# %lu unsigned long Exactly equivalent to printf("%lu").
# %zd Py_ssize_t Exactly equivalent to printf("%zd").
# %zu size_t Exactly equivalent to printf("%zu").
# %i int Exactly equivalent to printf("%i").
# %x int Exactly equivalent to printf("%x").
# %s char* A null-terminated C character array.
# %p void* The hex representation of a C pointer.
# Mostly equivalent to printf("%p") except that it is guaranteed to
# start with the literal 0x regardless of what the platform's printf
# yields.
# An unrecognized format character causes all the rest of the
# format string to be copied as-is to the result string, and any
# extra arguments discarded.
object PyString_FromFormatV(char *format, va_list vargs)
# Return value: New reference.
# Identical to PyString_FromFormat() except that it takes exactly two arguments.
Py_ssize_t PyString_Size(object string) except -1
# Return the length of the string in string object string.
Py_ssize_t PyString_GET_SIZE(object string)
# Macro form of PyString_Size() but without error checking.
char* PyString_AsString(object string) except NULL
# Return a NUL-terminated representation of the contents of
# string. The pointer refers to the internal buffer of string, not
# a copy. The data must not be modified in any way, unless the
# string was just created using PyString_FromStringAndSize(NULL,
# size). It must not be deallocated. If string is a Unicode
# object, this function computes the default encoding of string
# and operates on that. If string is not a string object at all,
# PyString_AsString() returns NULL and raises TypeError.
char* PyString_AS_STRING(object string)
# Macro form of PyString_AsString() but without error
# checking. Only string objects are supported; no Unicode objects
# should be passed.
int PyString_AsStringAndSize(object obj, char **buffer, Py_ssize_t *length) except -1
# Return a NULL-terminated representation of the contents of the
# object obj through the output variables buffer and length.
#
# The function accepts both string and Unicode objects as
# input. For Unicode objects it returns the default encoded
# version of the object. If length is NULL, the resulting buffer
# may not contain NUL characters; if it does, the function returns
# -1 and a TypeError is raised.
# The buffer refers to an internal string buffer of obj, not a
# copy. The data must not be modified in any way, unless the
# string was just created using PyString_FromStringAndSize(NULL,
# size). It must not be deallocated. If string is a Unicode
# object, this function computes the default encoding of string
# and operates on that. If string is not a string object at all,
# PyString_AsStringAndSize() returns -1 and raises TypeError.
void PyString_Concat(PyObject **string, object newpart)
# Create a new string object in *string containing the contents of
# newpart appended to string; the caller will own the new
# reference. The reference to the old value of string will be
# stolen. If the new string cannot be created, the old reference
# to string will still be discarded and the value of *string will
# be set to NULL; the appropriate exception will be set.
void PyString_ConcatAndDel(PyObject **string, object newpart)
# Create a new string object in *string containing the contents of
# newpart appended to string. This version decrements the
# reference count of newpart.
int _PyString_Resize(PyObject **string, Py_ssize_t newsize) except -1
# A way to resize a string object even though it is
# ``immutable''. Only use this to build up a brand new string
# object; don't use this if the string may already be known in
# other parts of the code. It is an error to call this function if
# the refcount on the input string object is not one. Pass the
# address of an existing string object as an lvalue (it may be
# written into), and the new size desired. On success, *string
# holds the resized string object and 0 is returned; the address
# in *string may differ from its input value. If the reallocation
# fails, the original string object at *string is deallocated,
# *string is set to NULL, a memory exception is set, and -1 is
# returned.
object PyString_Format(object format, object args)
# Return value: New reference. Return a new string object from
# format and args. Analogous to format % args. The args argument
# must be a tuple.
void PyString_InternInPlace(PyObject **string)
# Intern the argument *string in place. The argument must be the
# address of a pointer variable pointing to a Python string
# object. If there is an existing interned string that is the same
# as *string, it sets *string to it (decrementing the reference
# count of the old string object and incrementing the reference
# count of the interned string object), otherwise it leaves
# *string alone and interns it (incrementing its reference
# count). (Clarification: even though there is a lot of talk about
# reference counts, think of this function as
# reference-count-neutral; you own the object after the call if
# and only if you owned it before the call.)
object PyString_InternFromString(char *v)
# Return value: New reference.
# A combination of PyString_FromString() and
# PyString_InternInPlace(), returning either a new string object
# that has been interned, or a new (``owned'') reference to an
# earlier interned string object with the same value.
object PyString_Decode(char *s, Py_ssize_t size, char *encoding, char *errors)
# Return value: New reference.
# Create an object by decoding size bytes of the encoded buffer s
# using the codec registered for encoding. encoding and errors
# have the same meaning as the parameters of the same name in the
# unicode() built-in function. The codec to be used is looked up
# using the Python codec registry. Return NULL if an exception was
# raised by the codec.
object PyString_AsDecodedObject(object str, char *encoding, char *errors)
# Return value: New reference.
# Decode a string object by passing it to the codec registered for
# encoding and return the result as Python object. encoding and
# errors have the same meaning as the parameters of the same name
# in the string encode() method. The codec to be used is looked up
# using the Python codec registry. Return NULL if an exception was
# raised by the codec.
object PyString_Encode(char *s, Py_ssize_t size, char *encoding, char *errors)
# Return value: New reference.
# Encode the char buffer of the given size by passing it to the
# codec registered for encoding and return a Python
# object. encoding and errors have the same meaning as the
# parameters of the same name in the string encode() method. The
# codec to be used is looked up using the Python codec
# registry. Return NULL if an exception was raised by the codec.
object PyString_AsEncodedObject(object str, char *encoding, char *errors)
# Return value: New reference.
# Encode a string object using the codec registered for encoding
# and return the result as Python object. encoding and errors have
# the same meaning as the parameters of the same name in the
# string encode() method. The codec to be used is looked up using
# the Python codec registry. Return NULL if an exception was
# raised by the codec.
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/tuple.pxd 0000664 0000000 0000000 00000006166 11446142532 0026321 0 ustar 00root root 0000000 0000000 from cpython.ref cimport PyObject
cdef extern from "Python.h":
############################################################################
# Tuples
############################################################################
bint PyTuple_Check(object p)
# Return true if p is a tuple object or an instance of a subtype
# of the tuple type.
bint PyTuple_CheckExact(object p)
# Return true if p is a tuple object, but not an instance of a subtype of the tuple type.
tuple PyTuple_New(Py_ssize_t len)
# Return value: New reference.
# Return a new tuple object of size len, or NULL on failure.
tuple PyTuple_Pack(Py_ssize_t n, ...)
# Return value: New reference.
# Return a new tuple object of size n, or NULL on failure. The
# tuple values are initialized to the subsequent n C arguments
# pointing to Python objects. "PyTuple_Pack(2, a, b)" is
# equivalent to "Py_BuildValue("(OO)", a, b)".
int PyTuple_Size(object p) except -1
# Take a pointer to a tuple object, and return the size of that tuple.
int PyTuple_GET_SIZE(object p)
# Return the size of the tuple p, which must be non-NULL and point
# to a tuple; no error checking is performed.
PyObject* PyTuple_GetItem(object p, Py_ssize_t pos) except NULL
# Return value: Borrowed reference.
# Return the object at position pos in the tuple pointed to by
# p. If pos is out of bounds, return NULL and sets an IndexError
# exception.
PyObject* PyTuple_GET_ITEM(object p, Py_ssize_t pos)
# Return value: Borrowed reference.
# Like PyTuple_GetItem(), but does no checking of its arguments.
tuple PyTuple_GetSlice(object p, Py_ssize_t low, Py_ssize_t high)
# Return value: New reference.
# Take a slice of the tuple pointed to by p from low to high and return it as a new tuple.
int PyTuple_SetItem(object p, Py_ssize_t pos, object o)
# Insert a reference to object o at position pos of the tuple
# pointed to by p. Return 0 on success. Note: This function
# ``steals'' a reference to o.
void PyTuple_SET_ITEM(object p, Py_ssize_t pos, object o)
# Like PyTuple_SetItem(), but does no error checking, and should
# only be used to fill in brand new tuples. Note: This function
# ``steals'' a reference to o.
int _PyTuple_Resize(PyObject **p, Py_ssize_t newsize) except -1
# Can be used to resize a tuple. newsize will be the new length of
# the tuple. Because tuples are supposed to be immutable, this
# should only be used if there is only one reference to the
# object. Do not use this if the tuple may already be known to
# some other part of the code. The tuple will always grow or
# shrink at the end. Think of this as destroying the old tuple and
# creating a new one, only more efficiently. Returns 0 on
# success. Client code should never assume that the resulting
# value of *p will be the same as before calling this function. If
# the object referenced by *p is replaced, the original *p is
# destroyed. On failure, returns -1 and sets *p to NULL, and
# raises MemoryError or SystemError.
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/type.pxd 0000664 0000000 0000000 00000003351 11446142532 0026142 0 ustar 00root root 0000000 0000000
cdef extern from "Python.h":
# The C structure of the objects used to describe built-in types.
############################################################################
# 7.1.1 Type Objects
############################################################################
# PyObject* PyType_Type
# This is the type object for type objects; it is the same object
# as type and types.TypeType in the Python layer.
bint PyType_Check(object o)
# Return true if the object o is a type object, including
# instances of types derived from the standard type object. Return
# false in all other cases.
bint PyType_CheckExact(object o)
# Return true if the object o is a type object, but not a subtype
# of the standard type object. Return false in all other
# cases.
bint PyType_HasFeature(object o, int feature)
# Return true if the type object o sets the feature feature. Type
# features are denoted by single bit flags.
bint PyType_IS_GC(object o)
# Return true if the type object includes support for the cycle
# detector; this tests the type flag Py_TPFLAGS_HAVE_GC.
bint PyType_IsSubtype(object a, object b)
# Return true if a is a subtype of b.
object PyType_GenericAlloc(object type, Py_ssize_t nitems)
# Return value: New reference.
object PyType_GenericNew(object type, object args, object kwds)
# Return value: New reference.
bint PyType_Ready(object type) except -1
# Finalize a type object. This should be called on all type
# objects to finish their initialization. This function is
# responsible for adding inherited slots from a type's base
# class. Return 0 on success, or return -1 and sets an exception
# on error.
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/unicode.pxd 0000664 0000000 0000000 00000043363 11446142532 0026616 0 ustar 00root root 0000000 0000000 cdef extern from *:
# Return true if the object o is a Unicode object or an instance
# of a Unicode subtype. Changed in version 2.2: Allowed subtypes
# to be accepted.
bint PyUnicode_Check(object o)
# Return true if the object o is a Unicode object, but not an
# instance of a subtype. New in version 2.2.
bint PyUnicode_CheckExact(object o)
# Return the size of the object. o has to be a PyUnicodeObject
# (not checked).
Py_ssize_t PyUnicode_GET_SIZE(object o)
# Return the size of the object's internal buffer in bytes. o has
# to be a PyUnicodeObject (not checked).
Py_ssize_t PyUnicode_GET_DATA_SIZE(object o)
# Return a pointer to the internal Py_UNICODE buffer of the
# object. o has to be a PyUnicodeObject (not checked).
Py_UNICODE* PyUnicode_AS_UNICODE(object o)
# Return a pointer to the internal buffer of the object. o has to
# be a PyUnicodeObject (not checked).
char* PyUnicode_AS_DATA(object o)
# Return 1 or 0 depending on whether ch is a whitespace character.
bint Py_UNICODE_ISSPACE(Py_UNICODE ch)
# Return 1 or 0 depending on whether ch is a lowercase character.
bint Py_UNICODE_ISLOWER(Py_UNICODE ch)
# Return 1 or 0 depending on whether ch is an uppercase character.
bint Py_UNICODE_ISUPPER(Py_UNICODE ch)
# Return 1 or 0 depending on whether ch is a titlecase character.
bint Py_UNICODE_ISTITLE(Py_UNICODE ch)
# Return 1 or 0 depending on whether ch is a linebreak character.
bint Py_UNICODE_ISLINEBREAK(Py_UNICODE ch)
# Return 1 or 0 depending on whether ch is a decimal character.
bint Py_UNICODE_ISDECIMAL(Py_UNICODE ch)
# Return 1 or 0 depending on whether ch is a digit character.
bint Py_UNICODE_ISDIGIT(Py_UNICODE ch)
# Return 1 or 0 depending on whether ch is a numeric character.
bint Py_UNICODE_ISNUMERIC(Py_UNICODE ch)
# Return 1 or 0 depending on whether ch is an alphabetic character.
bint Py_UNICODE_ISALPHA(Py_UNICODE ch)
# Return 1 or 0 depending on whether ch is an alphanumeric character.
bint Py_UNICODE_ISALNUM(Py_UNICODE ch)
# Return the character ch converted to lower case.
Py_UNICODE Py_UNICODE_TOLOWER(Py_UNICODE ch)
# Return the character ch converted to upper case.
Py_UNICODE Py_UNICODE_TOUPPER(Py_UNICODE ch)
# Return the character ch converted to title case.
Py_UNICODE Py_UNICODE_TOTITLE(Py_UNICODE ch)
# Return the character ch converted to a decimal positive
# integer. Return -1 if this is not possible. This macro does not
# raise exceptions.
int Py_UNICODE_TODECIMAL(Py_UNICODE ch)
# Return the character ch converted to a single digit
# integer. Return -1 if this is not possible. This macro does not
# raise exceptions.
int Py_UNICODE_TODIGIT(Py_UNICODE ch)
# Return the character ch converted to a double. Return -1.0 if
# this is not possible. This macro does not raise exceptions.
double Py_UNICODE_TONUMERIC(Py_UNICODE ch)
# To create Unicode objects and access their basic sequence
# properties, use these APIs:
# Create a Unicode Object from the Py_UNICODE buffer u of the
# given size. u may be NULL which causes the contents to be
# undefined. It is the user's responsibility to fill in the needed
# data. The buffer is copied into the new object. If the buffer is
# not NULL, the return value might be a shared object. Therefore,
# modification of the resulting Unicode object is only allowed
# when u is NULL.
object PyUnicode_FromUnicode(Py_UNICODE *u, Py_ssize_t size)
# Create a Unicode Object from the given Unicode code point ordinal.
#
# The ordinal must be in range(0x10000) on narrow Python builds
# (UCS2), and range(0x110000) on wide builds (UCS4). A ValueError
# is raised in case it is not.
object PyUnicode_FromOrdinal(int ordinal)
# Return a read-only pointer to the Unicode object's internal
# Py_UNICODE buffer, NULL if unicode is not a Unicode object.
Py_UNICODE* PyUnicode_AsUnicode(object o) except NULL
# Return the length of the Unicode object.
Py_ssize_t PyUnicode_GetSize(object o) except -1
# Coerce an encoded object obj to an Unicode object and return a
# reference with incremented refcount.
# String and other char buffer compatible objects are decoded
# according to the given encoding and using the error handling
# defined by errors. Both can be NULL to have the interface use
# the default values (see the next section for details).
# All other objects, including Unicode objects, cause a TypeError
# to be set.
object PyUnicode_FromEncodedObject(object o, char *encoding, char *errors)
# Shortcut for PyUnicode_FromEncodedObject(obj, NULL, "strict")
# which is used throughout the interpreter whenever coercion to
# Unicode is needed.
object PyUnicode_FromObject(object obj)
# If the platform supports wchar_t and provides a header file
# wchar.h, Python can interface directly to this type using the
# following functions. Support is optimized if Python's own
# Py_UNICODE type is identical to the system's wchar_t.
#ctypedef int wchar_t
# Create a Unicode object from the wchar_t buffer w of the given
# size. Return NULL on failure.
#PyObject* PyUnicode_FromWideChar(wchar_t *w, Py_ssize_t size)
#Py_ssize_t PyUnicode_AsWideChar(object o, wchar_t *w, Py_ssize_t size)
# Codecs
# Create a Unicode object by decoding size bytes of the encoded
# string s. encoding and errors have the same meaning as the
# parameters of the same name in the unicode() builtin
# function. The codec to be used is looked up using the Python
# codec registry. Return NULL if an exception was raised by the
# codec.
object PyUnicode_Decode(char *s, Py_ssize_t size, char *encoding, char *errors)
# Encode the Py_UNICODE buffer of the given size and return a
# Python string object. encoding and errors have the same meaning
# as the parameters of the same name in the Unicode encode()
# method. The codec to be used is looked up using the Python codec
# registry. Return NULL if an exception was raised by the codec.
object PyUnicode_Encode(Py_UNICODE *s, Py_ssize_t size,
char *encoding, char *errors)
# Encode a Unicode object and return the result as Python string
# object. encoding and errors have the same meaning as the
# parameters of the same name in the Unicode encode() method. The
# codec to be used is looked up using the Python codec
# registry. Return NULL if an exception was raised by the codec.
object PyUnicode_AsEncodedString(object unicode, char *encoding, char *errors)
# These are the UTF-8 codec APIs:
# Create a Unicode object by decoding size bytes of the UTF-8
# encoded string s. Return NULL if an exception was raised by the
# codec.
object PyUnicode_DecodeUTF8(char *s, Py_ssize_t size, char *errors)
# If consumed is NULL, behave like PyUnicode_DecodeUTF8(). If
# consumed is not NULL, trailing incomplete UTF-8 byte sequences
# will not be treated as an error. Those bytes will not be decoded
# and the number of bytes that have been decoded will be stored in
# consumed. New in version 2.4.
object PyUnicode_DecodeUTF8Stateful(char *s, Py_ssize_t size, char *errors, Py_ssize_t *consumed)
# Encode the Py_UNICODE buffer of the given size using UTF-8 and
# return a Python string object. Return NULL if an exception was
# raised by the codec.
object PyUnicode_EncodeUTF8(Py_UNICODE *s, Py_ssize_t size, char *errors)
# Encode a Unicode objects using UTF-8 and return the result as Python string object. Error handling is ``strict''. Return NULL if an exception was raised by the codec.
object PyUnicode_AsUTF8String(object unicode)
# These are the UTF-16 codec APIs:
# Decode length bytes from a UTF-16 encoded buffer string and
# return the corresponding Unicode object. errors (if non-NULL)
# defines the error handling. It defaults to ``strict''.
#
# If byteorder is non-NULL, the decoder starts decoding using the
# given byte order:
#
# *byteorder == -1: little endian
# *byteorder == 0: native order
# *byteorder == 1: big endian
#
# and then switches if the first two bytes of the input data are a
# byte order mark (BOM) and the specified byte order is native
# order. This BOM is not copied into the resulting Unicode
# string. After completion, *byteorder is set to the current byte
# order at the.
#
# If byteorder is NULL, the codec starts in native order mode.
object PyUnicode_DecodeUTF16(char *s, Py_ssize_t size, char *errors, int *byteorder)
# If consumed is NULL, behave like PyUnicode_DecodeUTF16(). If
# consumed is not NULL, PyUnicode_DecodeUTF16Stateful() will not
# treat trailing incomplete UTF-16 byte sequences (such as an odd
# number of bytes or a split surrogate pair) as an error. Those
# bytes will not be decoded and the number of bytes that have been
# decoded will be stored in consumed. New in version 2.4.
object PyUnicode_DecodeUTF16Stateful(char *s, Py_ssize_t size, char *errors, int *byteorder, Py_ssize_t *consumed)
# Return a Python string object holding the UTF-16 encoded value
# of the Unicode data in s. If byteorder is not 0, output is
# written according to the following byte order:
#
# byteorder == -1: little endian
# byteorder == 0: native byte order (writes a BOM mark)
# byteorder == 1: big endian
#
# If byteorder is 0, the output string will always start with the
# Unicode BOM mark (U+FEFF). In the other two modes, no BOM mark
# is prepended.
#
# If Py_UNICODE_WIDE is defined, a single Py_UNICODE value may get
# represented as a surrogate pair. If it is not defined, each
# Py_UNICODE values is interpreted as an UCS-2 character.
object PyUnicode_EncodeUTF16(Py_UNICODE *s, Py_ssize_t size, char *errors, int byteorder)
# Return a Python string using the UTF-16 encoding in native byte
# order. The string always starts with a BOM mark. Error handling
# is ``strict''. Return NULL if an exception was raised by the
# codec.
object PyUnicode_AsUTF16String(object unicode)
# These are the ``Unicode Escape'' codec APIs:
# Create a Unicode object by decoding size bytes of the
# Unicode-Escape encoded string s. Return NULL if an exception was
# raised by the codec.
object PyUnicode_DecodeUnicodeEscape(char *s, Py_ssize_t size, char *errors)
# Encode the Py_UNICODE buffer of the given size using
# Unicode-Escape and return a Python string object. Return NULL if
# an exception was raised by the codec.
object PyUnicode_EncodeUnicodeEscape(Py_UNICODE *s, Py_ssize_t size)
# Encode a Unicode objects using Unicode-Escape and return the
# result as Python string object. Error handling is
# ``strict''. Return NULL if an exception was raised by the codec.
object PyUnicode_AsUnicodeEscapeString(object unicode)
# These are the ``Raw Unicode Escape'' codec APIs:
# Create a Unicode object by decoding size bytes of the
# Raw-Unicode-Escape encoded string s. Return NULL if an exception
# was raised by the codec.
object PyUnicode_DecodeRawUnicodeEscape(char *s, Py_ssize_t size, char *errors)
# Encode the Py_UNICODE buffer of the given size using
# Raw-Unicode-Escape and return a Python string object. Return
# NULL if an exception was raised by the codec.
object PyUnicode_EncodeRawUnicodeEscape(Py_UNICODE *s, Py_ssize_t size, char *errors)
# Encode a Unicode objects using Raw-Unicode-Escape and return the
# result as Python string object. Error handling is
# ``strict''. Return NULL if an exception was raised by the codec.
object PyUnicode_AsRawUnicodeEscapeString(object unicode)
# These are the Latin-1 codec APIs: Latin-1 corresponds to the first 256 Unicode ordinals and only these are accepted by the codecs during encoding.
# Create a Unicode object by decoding size bytes of the Latin-1
# encoded string s. Return NULL if an exception was raised by the
# codec.
object PyUnicode_DecodeLatin1(char *s, Py_ssize_t size, char *errors)
# Encode the Py_UNICODE buffer of the given size using Latin-1 and
# return a Python string object. Return NULL if an exception was
# raised by the codec.
object PyUnicode_EncodeLatin1(Py_UNICODE *s, Py_ssize_t size, char *errors)
# Encode a Unicode objects using Latin-1 and return the result as
# Python string object. Error handling is ``strict''. Return NULL
# if an exception was raised by the codec.
object PyUnicode_AsLatin1String(object unicode)
# These are the ASCII codec APIs. Only 7-bit ASCII data is
# accepted. All other codes generate errors.
# Create a Unicode object by decoding size bytes of the ASCII
# encoded string s. Return NULL if an exception was raised by the
# codec.
object PyUnicode_DecodeASCII(char *s, Py_ssize_t size, char *errors)
# Encode the Py_UNICODE buffer of the given size using ASCII and
# return a Python string object. Return NULL if an exception was
# raised by the codec.
object PyUnicode_EncodeASCII(Py_UNICODE *s, Py_ssize_t size, char *errors)
# Encode a Unicode objects using ASCII and return the result as
# Python string object. Error handling is ``strict''. Return NULL
# if an exception was raised by the codec.
object PyUnicode_AsASCIIString(object o)
# These are the mapping codec APIs:
#
# This codec is special in that it can be used to implement many
# different codecs (and this is in fact what was done to obtain most
# of the standard codecs included in the encodings package). The codec
# uses mapping to encode and decode characters.
#
# Decoding mappings must map single string characters to single
# Unicode characters, integers (which are then interpreted as Unicode
# ordinals) or None (meaning "undefined mapping" and causing an
# error).
#
# Encoding mappings must map single Unicode characters to single
# string characters, integers (which are then interpreted as Latin-1
# ordinals) or None (meaning "undefined mapping" and causing an
# error).
#
# The mapping objects provided must only support the __getitem__
# mapping interface.
#
# If a character lookup fails with a LookupError, the character is
# copied as-is meaning that its ordinal value will be interpreted as
# Unicode or Latin-1 ordinal resp. Because of this, mappings only need
# to contain those mappings which map characters to different code
# points.
# Create a Unicode object by decoding size bytes of the encoded
# string s using the given mapping object. Return NULL if an
# exception was raised by the codec. If mapping is NULL latin-1
# decoding will be done. Else it can be a dictionary mapping byte
# or a unicode string, which is treated as a lookup table. Byte
# values greater that the length of the string and U+FFFE
# "characters" are treated as "undefined mapping". Changed in
# version 2.4: Allowed unicode string as mapping argument.
object PyUnicode_DecodeCharmap(char *s, Py_ssize_t size, object mapping, char *errors)
# Encode the Py_UNICODE buffer of the given size using the given
# mapping object and return a Python string object. Return NULL if
# an exception was raised by the codec.
object PyUnicode_EncodeCharmap(Py_UNICODE *s, Py_ssize_t size, object mapping, char *errors)
# Encode a Unicode objects using the given mapping object and
# return the result as Python string object. Error handling is
# ``strict''. Return NULL if an exception was raised by the codec.
object PyUnicode_AsCharmapString(object o, object mapping)
# The following codec API is special in that maps Unicode to Unicode.
# Translate a Py_UNICODE buffer of the given length by applying a
# character mapping table to it and return the resulting Unicode
# object. Return NULL when an exception was raised by the codec.
#
# The mapping table must map Unicode ordinal integers to Unicode
# ordinal integers or None (causing deletion of the character).
#
# Mapping tables need only provide the __getitem__() interface;
# dictionaries and sequences work well. Unmapped character
# ordinals (ones which cause a LookupError) are left untouched and
# are copied as-is.
object PyUnicode_TranslateCharmap(Py_UNICODE *s, Py_ssize_t size,
object table, char *errors)
# These are the MBCS codec APIs. They are currently only available on
# Windows and use the Win32 MBCS converters to implement the
# conversions. Note that MBCS (or DBCS) is a class of encodings, not
# just one. The target encoding is defined by the user settings on the
# machine running the codec.
# Create a Unicode object by decoding size bytes of the MBCS
# encoded string s. Return NULL if an exception was raised by the
# codec.
object PyUnicode_DecodeMBCS(char *s, Py_ssize_t size, char *errors)
# If consumed is NULL, behave like PyUnicode_DecodeMBCS(). If
# consumed is not NULL, PyUnicode_DecodeMBCSStateful() will not
# decode trailing lead byte and the number of bytes that have been
# decoded will be stored in consumed. New in version 2.5.
object PyUnicode_DecodeMBCSStateful(char *s, int size, char *errors, int *consumed)
# Encode the Py_UNICODE buffer of the given size using MBCS and
# return a Python string object. Return NULL if an exception was
# raised by the codec.
object PyUnicode_EncodeMBCS(Py_UNICODE *s, Py_ssize_t size, char *errors)
# Encode a Unicode objects using MBCS and return the result as
# Python string object. Error handling is ``strict''. Return NULL
# if an exception was raised by the codec.
object PyUnicode_AsMBCSString(object o)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/version.pxd 0000664 0000000 0000000 00000001517 11446142532 0026650 0 ustar 00root root 0000000 0000000 # Python version constants
#
# It's better to evaluate these at runtime (i.e. C compile time) using
#
# if PY_MAJOR_VERSION >= 3:
# do_stuff_in_Py3_0_and_later()
# if PY_VERSION_HEX >= 0x02050000:
# do_stuff_in_Py2_5_and_later()
#
# than using the IF/DEF statements, which are evaluated at Cython
# compile time. This will keep your C code portable.
cdef extern from *:
# the complete version, e.g. 0x010502B2 == 1.5.2b2
int PY_VERSION_HEX
# the individual sections as plain numbers
int PY_MAJOR_VERSION
int PY_MINOR_VERSION
int PY_MICRO_VERSION
int PY_RELEASE_LEVEL
int PY_RELEASE_SERIAL
# Note: PY_RELEASE_LEVEL is one of
# 0xA (alpha)
# 0xB (beta)
# 0xC (release candidate)
# 0xF (final)
char PY_VERSION[]
char PY_PATCHLEVEL_REVISION[]
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/cpython/weakref.pxd 0000664 0000000 0000000 00000003670 11446142532 0026611 0 ustar 00root root 0000000 0000000 from cpython.ref cimport PyObject
cdef extern from "Python.h":
bint PyWeakref_Check(object ob)
# Return true if ob is either a reference or proxy object.
bint PyWeakref_CheckRef(object ob)
# Return true if ob is a reference object.
bint PyWeakref_CheckProxy(ob)
# Return true if *ob* is a proxy object.
object PyWeakref_NewRef(object ob, object callback)
# Return a weak reference object for the object ob. This will
# always return a new reference, but is not guaranteed to create a
# new object; an existing reference object may be returned. The
# second parameter, callback, can be a callable object that
# receives notification when ob is garbage collected; it should
# accept a single parameter, which will be the weak reference
# object itself. callback may also be None or NULL. If ob is not
# a weakly-referencable object, or if callback is not callable,
# None, or NULL, this will return NULL and raise TypeError.
object PyWeakref_NewProxy(object ob, object callback)
# Return a weak reference proxy object for the object ob. This
# will always return a new reference, but is not guaranteed to
# create a new object; an existing proxy object may be returned.
# The second parameter, callback, can be a callable object that
# receives notification when ob is garbage collected; it should
# accept a single parameter, which will be the weak reference
# object itself. callback may also be None or NULL. If ob is not
# a weakly-referencable object, or if callback is not callable,
# None, or NULL, this will return NULL and raise TypeError.
PyObject* PyWeakref_GetObject(object ref)
# Return the referenced object from a weak reference, ref. If the
# referent is no longer live, returns None.
PyObject* PyWeakref_GET_OBJECT(object ref)
# Similar to PyWeakref_GetObject, but implemented as a macro that
# does no error checking.
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/libc/ 0000775 0000000 0000000 00000000000 11446142532 0023667 5 ustar 00root root 0000000 0000000 cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/libc/__init__.pxd 0000664 0000000 0000000 00000000015 11446142532 0026137 0 ustar 00root root 0000000 0000000 # empty file
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/libc/errno.pxd 0000664 0000000 0000000 00000000174 11446142532 0025533 0 ustar 00root root 0000000 0000000 # 7.5 Errors
cdef extern from "errno.h" nogil:
enum: EDOM
enum: EILSEQ
enum: ERANGE
int errno
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/libc/float.pxd 0000664 0000000 0000000 00000001350 11446142532 0025510 0 ustar 00root root 0000000 0000000 # 5.2.4.2.2 Characteristics of floating types
cdef extern from "float.h":
enum: FLT_RADIX
enum: FLT_MANT_DIG
enum: DBL_MANT_DIG
enum: LDBL_MANT_DIG
enum: DECIMAL_DIG
enum: FLT_DIG
enum: DBL_DIG
enum: LDBL_DIG
enum: FLT_MIN_EXP
enum: DBL_MIN_EXP
enum: LDBL_MIN_EXP
enum: FLT_MIN_10_EXP
enum: DBL_MIN_10_EXP
enum: LDBL_MIN_10_EXP
enum: FLT_MAX_EXP
enum: DBL_MAX_EXP
enum: LDBL_MAX_EXP
enum: FLT_MAX_10_EXP
enum: DBL_MAX_10_EXP
enum: LDBL_MAX_10_EXP
enum: FLT_MAX
enum: DBL_MAX
enum: LDBL_MAX
enum: FLT_EPSILON
enum: DBL_EPSILON
enum: LDBL_EPSILON
enum: FLT_MIN
enum: DBL_MIN
enum: LDBL_MIN
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/libc/limits.pxd 0000664 0000000 0000000 00000000733 11446142532 0025710 0 ustar 00root root 0000000 0000000 # 5.2.4.2.1 Sizes of integer types
cdef extern from "limits.h":
enum: CHAR_BIT
enum: MB_LEN_MAX
enum: CHAR_MIN
enum: CHAR_MAX
enum: SCHAR_MIN
enum: SCHAR_MAX
enum: UCHAR_MAX
enum: SHRT_MIN
enum: SHRT_MAX
enum: USHRT_MAX
enum: INT_MIN
enum: INT_MAX
enum: UINT_MAX
enum: LONG_MIN
enum: LONG_MAX
enum: ULONG_MAX
enum: LLONG_MIN
enum: LLONG_MAX
enum: ULLONG_MAX
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/libc/locale.pxd 0000664 0000000 0000000 00000002123 11446142532 0025641 0 ustar 00root root 0000000 0000000 # 7.11 Localization
cdef extern from *:
ctypedef char const_char "const char"
cdef extern from "locale.h":
struct lconv:
char *decimal_point
char *thousands_sep
char *grouping
char *mon_decimal_point
char *mon_thousands_sep
char *mon_grouping
char *positive_sign
char *negative_sign
char *currency_symbol
char frac_digits
char p_cs_precedes
char n_cs_precedes
char p_sep_by_space
char n_sep_by_space
char p_sign_posn
char n_sign_posn
char *int_curr_symbol
char int_frac_digits
char int_p_cs_precedes
char int_n_cs_precedes
char int_p_sep_by_space
char int_n_sep_by_space
char int_p_sign_posn
char int_n_sign_posn
enum: LC_ALL
enum: LC_COLLATE
enum: LC_CTYPE
enum: LC_MONETARY
enum: LC_NUMERIC
enum: LC_TIME
# 7.11.1 Locale control
char *setlocale (int CATEGORY, const_char *LOCALE)
# 7.11.2 Numeric formatting convention inquiry
lconv *localeconv ()
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/libc/signal.pxd 0000664 0000000 0000000 00000002327 11446142532 0025665 0 ustar 00root root 0000000 0000000 # 7.14 Signal handling
ctypedef void (*sighandler_t)(int SIGNUM) nogil
cdef extern from "signal.h" nogil:
ctypedef int sig_atomic_t
enum: SIGABRT
enum: SIGFPE
enum: SIGILL
enum: SIGINT
enum: SIGSEGV
enum: SIGTERM
sighandler_t SIG_DFL
sighandler_t SIG_IGN
sighandler_t SIG_ERR
sighandler_t signal (int SIGNUM, sighandler_t ACTION)
int raise_"raise" (int SIGNUM)
cdef extern from "signal.h" nogil:
# Program Error
enum: SIGFPE
enum: SIGILL
enum: SIGSEGV
enum: SIGBUS
enum: SIGABRT
enum: SIGIOT
enum: SIGTRAP
enum: SIGEMT
enum: SIGSYS
# Termination
enum: SIGTERM
enum: SIGINT
enum: SIGQUIT
enum: SIGKILL
enum: SIGHUP
# Alarm
enum: SIGALRM
enum: SIGVTALRM
enum: SIGPROF
# Asynchronous I/O
enum: SIGIO
enum: SIGURG
enum: SIGPOLL
# Job Control
enum: SIGCHLD
enum: SIGCLD
enum: SIGCONT
enum: SIGSTOP
enum: SIGTSTP
enum: SIGTTIN
enum: SIGTTOU
# Operation Error
enum: SIGPIPE
enum: SIGLOST
enum: SIGXCPU
enum: SIGXFSZ
# Miscellaneous
enum: SIGUSR1
enum: SIGUSR2
enum: SIGWINCH
enum: SIGINFO
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/libc/stddef.pxd 0000664 0000000 0000000 00000000242 11446142532 0025653 0 ustar 00root root 0000000 0000000 # 7.17 Common definitions
cdef extern from "stddef.h":
ctypedef signed int ptrdiff_t
ctypedef unsigned int size_t
ctypedef int wchar_t
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/libc/stdint.pxd 0000664 0000000 0000000 00000006323 11446142532 0025715 0 ustar 00root root 0000000 0000000 # Longness only used for type promotion.
# Actual compile time size used for conversions.
# 7.18 Integer types
cdef extern from "stdint.h" nogil:
# 7.18.1 Integer types
# 7.18.1.1 Exact-width integer types
ctypedef signed char int8_t
ctypedef signed short int16_t
ctypedef signed int int32_t
ctypedef signed long int64_t
ctypedef unsigned char uint8_t
ctypedef unsigned short uint16_t
ctypedef unsigned int uint32_t
ctypedef unsigned long uint64_t
# 7.18.1.2 Minimum-width integer types
ctypedef signed char int_least8_t
ctypedef signed short int_least16_t
ctypedef signed int int_least32_t
ctypedef signed long int_least64_t
ctypedef unsigned char uint_least8_t
ctypedef unsigned short uint_least16_t
ctypedef unsigned int uint_least32_t
ctypedef unsigned long uint_least64_t
# 7.18.1.3 Fastest minimum-width integer types
ctypedef signed char int_fast8_t
ctypedef signed short int_fast16_t
ctypedef signed int int_fast32_t
ctypedef signed long int_fast64_t
ctypedef unsigned char uint_fast8_t
ctypedef unsigned short uint_fast16_t
ctypedef unsigned int uint_fast32_t
ctypedef unsigned long uint_fast64_t
# 7.18.1.4 Integer types capable of holding object pointers
ctypedef ssize_t intptr_t
ctypedef size_t uintptr_t
# 7.18.1.5 Greatest-width integer types
ctypedef signed long long intmax_t
ctypedef unsigned long long uintmax_t
# 7.18.2 Limits of specified-width integer types
# 7.18.2.1 Limits of exact-width integer types
enum: INT8_T_MIN
enum: INT16_T_MIN
enum: INT32_T_MIN
enum: INT64_T_MIN
enum: INT8_T_MAX
enum: INT16_T_MAX
enum: INT32_T_MAX
enum: INT64_T_MAX
enum: UINT8_T_MAX
enum: UINT16_T_MAX
enum: UINT32_T_MAX
enum: UINT64_T_MAX
#7.18.2.2 Limits of minimum-width integer types
enum: INT_LEAST8_T_MIN
enum: INT_LEAST16_T_MIN
enum: INT_LEAST32_T_MIN
enum: INT_LEAST64_T_MIN
enum: INT_LEAST8_T_MAX
enum: INT_LEAST16_T_MAX
enum: INT_LEAST32_T_MAX
enum: INT_LEAST64_T_MAX
enum: UINT_LEAST8_T_MAX
enum: UINT_LEAST16_T_MAX
enum: UINT_LEAST32_T_MAX
enum: UINT_LEAST64_T_MAX
#7.18.2.3 Limits of fastest minimum-width integer types
enum: INT_FAST8_T_MIN
enum: INT_FAST16_T_MIN
enum: INT_FAST32_T_MIN
enum: INT_FAST64_T_MIN
enum: INT_FAST8_T_MAX
enum: INT_FAST16_T_MAX
enum: INT_FAST32_T_MAX
enum: INT_FAST64_T_MAX
enum: UINT_FAST8_T_MAX
enum: UINT_FAST16_T_MAX
enum: UINT_FAST32_T_MAX
enum: UINT_FAST64_T_MAX
#7.18.2.4 Limits of integer types capable of holding object pointers
enum: INTPTR_MIN
enum: INTPTR_MAX
enum: UINTPTR_MAX
# 7.18.2.5 Limits of greatest-width integer types
enum: INTMAX_T_MAX
enum: INTMAX_T_MIN
enum: UINTMAX_T_MAX
# 7.18.3 Limits of other integer types
# ptrdiff_t
enum: PTRDIFF_MIN
enum: PTRDIFF_MAX
# sig_atomic_t
enum: SIG_ATOMIC_MIN
enum: SIG_ATOMIC_MAX
# size_t
enum: SIZE_MAX
# wchar_t
enum: WCHAR_MIN
enum: WCHAR_MAX
# wint_t
enum: WINT_MIN
enum: WINT_MAX
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/libc/stdio.pxd 0000664 0000000 0000000 00000003730 11446142532 0025531 0 ustar 00root root 0000000 0000000 # 7.19 Input/output
cdef extern from *:
ctypedef char const_char "const char"
ctypedef void const_void "const void"
cdef extern from "stdio.h" nogil:
ctypedef struct FILE
cdef FILE *stdin
cdef FILE *stdout
cdef FILE *stderr
enum: FOPEN_MAX
enum: FILENAME_MAX
FILE *fopen (const_char *FILENAME, const_char *OPENTYPE)
FILE *freopen (const_char *FILENAME, const_char *OPENTYPE, FILE *STREAM)
int fclose (FILE *STREAM)
int remove (const_char *FILENAME)
int rename (const_char *OLDNAME, const_char *NEWNAME)
FILE *tmpfile ()
enum: _IOFBF
enum: _IOLBF
enum: _IONBF
int setvbuf (FILE *STREAM, char *BUF, int MODE, size_t SIZE)
enum: BUFSIZ
void setbuf (FILE *STREAM, char *BUF)
size_t fread (void *DATA, size_t SIZE, size_t COUNT, FILE *STREAM)
size_t fwrite (const_void *DATA, size_t SIZE, size_t COUNT, FILE *STREAM)
int fflush (FILE *STREAM)
enum: EOF
int feof (FILE *STREAM)
int ferror (FILE *STREAM)
enum: SEEK_SET
enum: SEEK_CUR
enum: SEEK_END
int fseek (FILE *STREAM, long int OFFSET, int WHENCE)
void rewind (FILE *STREAM)
long int ftell (FILE *STREAM)
ctypedef long long int fpos_t
ctypedef fpos_t const_fpos_t "const fpos_t"
int fgetpos (FILE *STREAM, fpos_t *POSITION)
int fsetpos (FILE *STREAM, const_fpos_t *POSITION)
int scanf (const_char *TEMPLATE, ...)
int sscanf (const_char *S, const_char *TEMPLATE, ...)
int fscanf (FILE *STREAM, const_char *TEMPLATE, ...)
int printf (const_char *TEMPLATE, ...)
int sprintf (char *S, const_char *TEMPLATE, ...)
int snprintf (char *S, size_t SIZE, const_char *TEMPLATE, ...)
int fprintf (FILE *STREAM, const_char *TEMPLATE, ...)
void perror (const_char *MESSAGE)
char *gets (char *S)
char *fgets (char *S, int COUNT, FILE *STREAM)
int puts (const_char *S)
int fputs (const_char *S, FILE *STREAM)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/libc/stdlib.pxd 0000664 0000000 0000000 00000004623 11446142532 0025672 0 ustar 00root root 0000000 0000000 # 7.20 General utilities
cdef extern from *:
ctypedef char const_char "const char"
ctypedef void const_void "const void"
cdef extern from "stdlib.h" nogil:
# 7.20.1 Numeric conversion functions
int atoi (const_char *STRING)
long atol (const_char *STRING)
long long atoll (const_char *STRING)
double atof (const_char *STRING)
long strtol (const_char *STRING, char **TAILPTR, int BASE)
unsigned long int strtoul (const_char *STRING, char **TAILPTR, int BASE)
long long int strtoll (const_char *STRING, char **TAILPTR, int BASE)
unsigned long long int strtoull (const_char *STRING, char **TAILPTR, int BASE)
float strtof (const_char *STRING, char **TAILPTR)
double strtod (const_char *STRING, char **TAILPTR)
long double strtold (const_char *STRING, char **TAILPTR)
# 7.20.2 Pseudo-random sequence generation functions
enum: RAND_MAX
int rand ()
void srand (unsigned int SEED)
# 7.20.3 Memory management functions
void *calloc (size_t COUNT, size_t ELTSIZE)
void free (void *PTR)
void *malloc (size_t SIZE)
void *realloc (void *PTR, size_t NEWSIZE)
# 7.20.4 Communication with the environment
enum: EXIT_FAILURE
enum: EXIT_SUCCESS
void exit (int STATUS)
void _Exit (int STATUS)
int atexit (void (*FUNCTION) ())
void abort ()
char *getenv (const_char *NAME)
int system (const_char *COMMAND)
#7.20.5 Searching and sorting utilities
void *bsearch (const_void *KEY, const_void *ARRAY,
size_t COUNT, size_t SIZE,
int (*COMPARE)(const_void *, const_void *))
void qsort (void *ARRAY, size_t COUNT, size_t SIZE,
int (*COMPARE)(const_void *, const_void *))
# 7.20.6 Integer arithmetic functions
int abs (int NUMBER)
long int labs (long int NUMBER)
long long int llabs (long long int NUMBER)
ctypedef struct div_t:
int quot
int rem
div_t div (int NUMERATOR, int DENOMINATOR)
ctypedef struct ldiv_t:
long int quot
long int rem
ldiv_t ldiv (long int NUMERATOR, long int DENOMINATOR)
ctypedef struct lldiv_t:
long long int quot
long long int rem
lldiv_t lldiv (long long int NUMERATOR, long long int DENOMINATOR)
# 7.20.7 Multibyte/wide character conversion functions
# XXX TODO
# 7.20.8 Multibyte/wide string conversion functions
# XXX TODO
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/libc/string.pxd 0000664 0000000 0000000 00000003315 11446142532 0025714 0 ustar 00root root 0000000 0000000 # 7.21 String handling
cdef extern from *:
ctypedef char const_char "const char"
ctypedef void const_void "const void"
cdef extern from "string.h" nogil:
void *memcpy (void *TO, const_void *FROM, size_t SIZE)
void *memmove (void *TO, const_void *FROM, size_t SIZE)
void *memset (void *BLOCK, int C, size_t SIZE)
int memcmp (const_void *A1, const_void *A2, size_t SIZE)
void *memchr (const_void *BLOCK, int C, size_t SIZE)
void *memchr (const_void *BLOCK, int C, size_t SIZE)
void *memrchr (const_void *BLOCK, int C, size_t SIZE)
size_t strlen (const_char *S)
char *strcpy (char *TO, const_char *FROM)
char *strncpy (char *TO, const_char *FROM, size_t SIZE)
char *strdup (const_char *S)
char *strndup (const_char *S, size_t SIZE)
char *strcat (char *TO, const_char *FROM)
char *strncat (char *TO, const_char *FROM, size_t SIZE)
int strcmp (const_char *S1, const_char *S2)
int strcasecmp (const_char *S1, const_char *S2)
int strncmp (const_char *S1, const_char *S2, size_t SIZE)
int strncasecmp (const_char *S1, const_char *S2, size_t N)
int strcoll (const_char *S1, const_char *S2)
size_t strxfrm (char *TO, const_char *FROM, size_t SIZE)
char *strchr (const_char *STRING, int C)
char *strrchr (const_char *STRING, int C)
char *strstr (const_char *HAYSTACK, const_char *NEEDLE)
char *strcasestr (const_char *HAYSTACK, const_char *NEEDLE)
size_t strcspn (const_char *STRING, const_char *STOPSET)
char * strpbrk (const_char *STRING, const_char *STOPSET)
char *strtok (char *NEWSTRING, const_char *DELIMITERS)
char *strsep (char **STRING_PTR, const_char *DELIMITER)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/libcpp/ 0000775 0000000 0000000 00000000000 11446142532 0024227 5 ustar 00root root 0000000 0000000 cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/libcpp/__init__.pxd 0000664 0000000 0000000 00000000071 11446142532 0026501 0 ustar 00root root 0000000 0000000 # empty file
cdef extern from *:
ctypedef bint bool
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/libcpp/deque.pxd 0000664 0000000 0000000 00000003704 11446142532 0026053 0 ustar 00root root 0000000 0000000 from pair cimport pair
cdef extern from "" namespace "std":
cdef cppclass deque[T]:
cppclass iterator:
T& operator*()
iterator operator++()
iterator operator--()
bint operator==(iterator)
bint operator!=(iterator)
cppclass reverse_iterator:
T& operator*()
iterator operator++()
iterator operator--()
bint operator==(iterator)
bint operator!=(iterator)
#cppclass const_iterator(iterator):
# pass
#cppclass const_reverse_iterator(reverse_iterator):
# pass
deque()
deque(deque&)
deque(size_t)
deque(size_t, T&)
#deque[input_iterator](input_iterator, input_iterator)
T& operator[](size_t)
#deque& operator=(deque&)
bint operator==(deque&, deque&)
bint operator!=(deque&, deque&)
bint operator<(deque&, deque&)
bint operator>(deque&, deque&)
bint operator<=(deque&, deque&)
bint operator>=(deque&, deque&)
void assign(size_t, T&)
void assign(input_iterator, input_iterator)
T& at(size_t)
T& back()
iterator begin()
#const_iterator begin()
void clear()
bint empty()
iterator end()
#const_iterator end()
iterator erase(iterator)
iterator erase(iterator, iterator)
T& front()
iterator insert(iterator, T&)
void insert(iterator, size_t, T&)
void insert(iterator, input_iterator, input_iterator)
size_t max_size()
void pop_back()
void pop_front()
void push_back(T&)
void push_front(T&)
reverse_iterator rbegin()
#const_reverse_iterator rbegin()
reverse_iterator rend()
#const_reverse_iterator rend()
void resize(size_t)
void resize(size_t, T&)
size_t size()
void swap(deque&)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/libcpp/list.pxd 0000664 0000000 0000000 00000003750 11446142532 0025724 0 ustar 00root root 0000000 0000000 cdef extern from "" namespace "std":
cdef cppclass list[T]:
cppclass iterator:
T& operator*()
iterator operator++()
iterator operator--()
bint operator==(iterator)
bint operator!=(iterator)
cppclass reverse_iterator:
T& operator*()
iterator operator++()
iterator operator--()
bint operator==(iterator)
bint operator!=(iterator)
#cppclass const_iterator(iterator):
# pass
#cppclass const_reverse_iterator(reverse_iterator):
# pass
list()
list(list&)
list(size_t, T&)
#list operator=(list&)
bint operator==(list&, list&)
bint operator!=(list&, list&)
bint operator<(list&, list&)
bint operator>(list&, list&)
bint operator<=(list&, list&)
bint operator>=(list&, list&)
void assign(size_t, T&)
T& back()
iterator begin()
#const_iterator begin()
bint empty()
iterator end()
#const_iterator end()
iterator erase(iterator)
iterator erase(iterator, iterator)
T& front()
iterator insert(iterator, T&)
void insert(iterator, size_t, T&)
size_t max_size()
void merge(list&)
#void merge(list&, BinPred)
void pop_back()
void pop_front()
void push_back(T&)
void push_front(T&)
reverse_iterator rbegin()
#const_reverse_iterator rbegin()
void remove(T&)
#void remove_if(UnPred)
reverse_iterator rend()
#const_reverse_iterator rend()
void resize(size_t, T&)
void reverse()
size_t size()
void sort()
#void sort(BinPred)
void splice(iterator, list&)
void splice(iterator, list&, iterator)
void splice(iterator, list&, iterator, iterator)
void swap(list&)
void unique()
#void unique(BinPred)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/libcpp/map.pxd 0000664 0000000 0000000 00000004040 11446142532 0025517 0 ustar 00root root 0000000 0000000 from pair cimport pair
cdef extern from "" namespace "std":
cdef cppclass map[T, U]:
cppclass iterator:
pair[T,U]& operator*()
iterator operator++()
iterator operator--()
bint operator==(iterator)
bint operator!=(iterator)
cppclass reverse_iterator:
pair[T,U] operator*()
iterator operator++()
iterator operator--()
bint operator==(iterator)
bint operator!=(iterator)
#cppclass const_iterator(iterator):
# pass
#cppclass const_reverse_iterator(reverse_iterator):
# pass
map()
map(map&)
#map(key_compare&)
U& operator[](T&)
#map& operator=(map&)
bint operator==(map&, map&)
bint operator!=(map&, map&)
bint operator<(map&, map&)
bint operator>(map&, map&)
bint operator<=(map&, map&)
bint operator>=(map&, map&)
U& at(T&)
iterator begin()
#const_iterator begin()
void clear()
size_t count(T&)
bint empty()
iterator end()
#const_iterator end()
pair[iterator, iterator] equal_range(T&)
#pair[const_iterator, const_iterator] equal_range(key_type&)
void erase(iterator)
void erase(iterator, iterator)
size_t erase(T&)
iterator find(T&)
#const_iterator find(key_type&)
pair[iterator, bint] insert(pair[T,U]) # XXX pair[T,U]&
iterator insert(iterator, pair[T,U]) # XXX pair[T,U]&
#void insert(input_iterator, input_iterator)
#key_compare key_comp()
iterator lower_bound(T&)
#const_iterator lower_bound(key_type&)
size_t max_size()
reverse_iterator rbegin()
#const_reverse_iterator rbegin()
reverse_iterator rend()
#const_reverse_iterator rend()
size_t size()
void swap(map&)
iterator upper_bound(T&)
#const_iterator upper_bound(key_type&)
#value_compare value_comp()
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/libcpp/pair.pxd 0000664 0000000 0000000 00000000245 11446142532 0025700 0 ustar 00root root 0000000 0000000 cdef extern from "" namespace "std":
cdef cppclass pair[T, U]:
T first
U second
pair()
pair(pair&)
pair(T&, U&)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/libcpp/queue.pxd 0000664 0000000 0000000 00000000761 11446142532 0026074 0 ustar 00root root 0000000 0000000 cdef extern from "" namespace "std":
cdef cppclass queue[T]:
queue()
queue(queue&)
#queue(Container&)
T& back()
bint empty()
T& front()
void pop()
void push(T&)
size_t size()
cdef cppclass priority_queue[T]:
priority_queue()
priority_queue(priority_queue&)
#priority_queue(Container&)
bint empty()
void pop()
void push(T&)
size_t size()
T& top()
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/libcpp/set.pxd 0000664 0000000 0000000 00000003624 11446142532 0025544 0 ustar 00root root 0000000 0000000 from pair cimport pair
cdef extern from "" namespace "std":
cdef cppclass set[T]:
cppclass iterator:
T operator*()
iterator operator++()
iterator operator--()
bint operator==(iterator)
bint operator!=(iterator)
cppclass reverse_iterator:
T operator*()
iterator operator++()
iterator operator--()
bint operator==(iterator)
bint operator!=(iterator)
#cppclass const_iterator(iterator):
# pass
#cppclass const_reverse_iterator(reverse_iterator):
# pass
set()
set(set&)
#set(key_compare&)
#set& operator=(set&)
bint operator==(set&, set&)
bint operator!=(set&, set&)
bint operator<(set&, set&)
bint operator>(set&, set&)
bint operator<=(set&, set&)
bint operator>=(set&, set&)
iterator begin()
#const_iterator begin()
void clear()
size_t count(T&)
bint empty()
iterator end()
#const_iterator end()
pair[iterator, iterator] equal_range(T&)
#pair[const_iterator, const_iterator] equal_range(T&)
void erase(iterator)
void erase(iterator, iterator)
size_t erase(T&)
iterator find(T&)
#const_iterator find(T&)
pair[iterator, bint] insert(T&)
iterator insert(iterator, T&)
#void insert(input_iterator, input_iterator)
#key_compare key_comp()
iterator lower_bound(T&)
#const_iterator lower_bound(T&)
size_t max_size()
reverse_iterator rbegin()
#const_reverse_iterator rbegin()
reverse_iterator rend()
#const_reverse_iterator rend()
size_t size()
void swap(set&)
iterator upper_bound(T&)
#const_iterator upper_bound(T&)
#value_compare value_comp()
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/libcpp/stack.pxd 0000664 0000000 0000000 00000000356 11446142532 0026055 0 ustar 00root root 0000000 0000000 cdef extern from "" namespace "std":
cdef cppclass stack[T]:
stack()
stack(stack&)
#stack(Container&)
bint empty()
void pop()
void push(T&)
size_t size()
T& top()
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/libcpp/vector.pxd 0000664 0000000 0000000 00000003712 11446142532 0026251 0 ustar 00root root 0000000 0000000 cdef extern from "" namespace "std":
cdef cppclass vector[T]:
cppclass iterator:
T& operator*()
iterator operator++()
iterator operator--()
bint operator==(iterator)
bint operator!=(iterator)
cppclass reverse_iterator:
T& operator*()
iterator operator++()
iterator operator--()
bint operator==(iterator)
bint operator!=(iterator)
#cppclass const_iterator(iterator):
# pass
#cppclass const_reverse_iterator(reverse_iterator):
# pass
vector()
vector(vector&)
vector(size_t)
vector(size_t, T&)
#vector[input_iterator](input_iterator, input_iterator)
T& operator[](size_t)
#vector& operator=(vector&)
bint operator==(vector&, vector&)
bint operator!=(vector&, vector&)
bint operator<(vector&, vector&)
bint operator>(vector&, vector&)
bint operator<=(vector&, vector&)
bint operator>=(vector&, vector&)
void assign(size_t, T&)
#void assign[input_iterator](input_iterator, input_iterator)
T& at(size_t)
T& back()
iterator begin()
#const_iterator begin()
size_t capacity()
void clear()
bint empty()
iterator end()
#const_iterator end()
iterator erase(iterator)
iterator erase(iterator, iterator)
T& front()
iterator insert(iterator, T&)
void insert(iterator, size_t, T&)
void insert(iterator, iterator, iterator)
size_t max_size()
void pop_back()
void push_back(T&)
reverse_iterator rbegin()
#const_reverse_iterator rbegin()
reverse_iterator rend()
#const_reverse_iterator rend()
void reserve(size_t)
void resize(size_t)
void resize(size_t, T&)
size_t size()
void swap(vector&)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/numpy.pxd 0000664 0000000 0000000 00000104660 11446142532 0024652 0 ustar 00root root 0000000 0000000 # NumPy static imports for Cython
#
# If any of the PyArray_* functions are called, import_array must be
# called first.
#
# This also defines backwards-compatability buffer acquisition
# code for use in Python 2.x (or Python <= 2.5 when NumPy starts
# implementing PEP-3118 directly).
#
# Because of laziness, the format string of the buffer is statically
# allocated. Increase the size if this is not enough, or submit a
# patch to do this properly.
#
# Author: Dag Sverre Seljebotn
#
DEF _buffer_format_string_len = 255
cimport cpython.buffer as pybuf
from cpython.ref cimport Py_INCREF, Py_XDECREF
from cpython.object cimport PyObject
cimport libc.stdlib as stdlib
cimport libc.stdio as stdio
cdef extern from "Python.h":
ctypedef int Py_intptr_t
cdef extern from "numpy/arrayobject.h":
ctypedef Py_intptr_t npy_intp
ctypedef size_t npy_uintp
cdef enum NPY_TYPES:
NPY_BOOL
NPY_BYTE
NPY_UBYTE
NPY_SHORT
NPY_USHORT
NPY_INT
NPY_UINT
NPY_LONG
NPY_ULONG
NPY_LONGLONG
NPY_ULONGLONG
NPY_FLOAT
NPY_DOUBLE
NPY_LONGDOUBLE
NPY_CFLOAT
NPY_CDOUBLE
NPY_CLONGDOUBLE
NPY_OBJECT
NPY_STRING
NPY_UNICODE
NPY_VOID
NPY_NTYPES
NPY_NOTYPE
NPY_INT8
NPY_INT16
NPY_INT32
NPY_INT64
NPY_INT128
NPY_INT256
NPY_UINT8
NPY_UINT16
NPY_UINT32
NPY_UINT64
NPY_UINT128
NPY_UINT256
NPY_FLOAT16
NPY_FLOAT32
NPY_FLOAT64
NPY_FLOAT80
NPY_FLOAT96
NPY_FLOAT128
NPY_FLOAT256
NPY_COMPLEX32
NPY_COMPLEX64
NPY_COMPLEX128
NPY_COMPLEX160
NPY_COMPLEX192
NPY_COMPLEX256
NPY_COMPLEX512
enum NPY_ORDER:
NPY_ANYORDER
NPY_CORDER
NPY_FORTRANORDER
enum NPY_CLIPMODE:
NPY_CLIP
NPY_WRAP
NPY_RAISE
enum NPY_SCALARKIND:
NPY_NOSCALAR,
NPY_BOOL_SCALAR,
NPY_INTPOS_SCALAR,
NPY_INTNEG_SCALAR,
NPY_FLOAT_SCALAR,
NPY_COMPLEX_SCALAR,
NPY_OBJECT_SCALAR
enum NPY_SORTKIND:
NPY_QUICKSORT
NPY_HEAPSORT
NPY_MERGESORT
cdef enum requirements:
NPY_C_CONTIGUOUS
NPY_F_CONTIGUOUS
NPY_CONTIGUOUS
NPY_FORTRAN
NPY_OWNDATA
NPY_FORCECAST
NPY_ENSURECOPY
NPY_ENSUREARRAY
NPY_ELEMENTSTRIDES
NPY_ALIGNED
NPY_NOTSWAPPED
NPY_WRITEABLE
NPY_UPDATEIFCOPY
NPY_ARR_HAS_DESCR
NPY_BEHAVED
NPY_BEHAVED_NS
NPY_CARRAY
NPY_CARRAY_RO
NPY_FARRAY
NPY_FARRAY_RO
NPY_DEFAULT
NPY_IN_ARRAY
NPY_OUT_ARRAY
NPY_INOUT_ARRAY
NPY_IN_FARRAY
NPY_OUT_FARRAY
NPY_INOUT_FARRAY
NPY_UPDATE_ALL
cdef enum:
NPY_MAXDIMS
npy_intp NPY_MAX_ELSIZE
ctypedef void (*PyArray_VectorUnaryFunc)(void *, void *, npy_intp, void *, void *)
ctypedef class numpy.dtype [object PyArray_Descr]:
# Use PyDataType_* macros when possible, however there are no macros
# for accessing some of the fields, so some are defined. Please
# ask on cython-dev if you need more.
cdef int type_num
cdef int itemsize "elsize"
cdef char byteorder
cdef object fields
cdef tuple names
ctypedef extern class numpy.flatiter [object PyArrayIterObject]:
# Use through macros
pass
ctypedef extern class numpy.broadcast [object PyArrayMultiIterObject]:
# Use through macros
pass
ctypedef struct PyArrayObject:
# For use in situations where ndarray can't replace PyArrayObject*,
# like PyArrayObject**.
pass
ctypedef class numpy.ndarray [object PyArrayObject]:
cdef __cythonbufferdefaults__ = {"mode": "strided"}
cdef:
# Only taking a few of the most commonly used and stable fields.
# One should use PyArray_* macros instead to access the C fields.
char *data
int ndim "nd"
npy_intp *shape "dimensions"
npy_intp *strides
dtype descr
PyObject* base
# Note: This syntax (function definition in pxd files) is an
# experimental exception made for __getbuffer__ and __releasebuffer__
# -- the details of this may change.
def __getbuffer__(ndarray self, Py_buffer* info, int flags):
# This implementation of getbuffer is geared towards Cython
# requirements, and does not yet fullfill the PEP.
# In particular strided access is always provided regardless
# of flags
cdef int copy_shape, i, ndim
cdef int endian_detector = 1
cdef bint little_endian = ((&endian_detector)[0] != 0)
ndim = PyArray_NDIM(self)
if sizeof(npy_intp) != sizeof(Py_ssize_t):
copy_shape = 1
else:
copy_shape = 0
if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS)
and not PyArray_CHKFLAGS(self, NPY_C_CONTIGUOUS)):
raise ValueError(u"ndarray is not C contiguous")
if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS)
and not PyArray_CHKFLAGS(self, NPY_F_CONTIGUOUS)):
raise ValueError(u"ndarray is not Fortran contiguous")
info.buf = PyArray_DATA(self)
info.ndim = ndim
if copy_shape:
# Allocate new buffer for strides and shape info. This is allocated
# as one block, strides first.
info.strides = stdlib.malloc(sizeof(Py_ssize_t) * ndim * 2)
info.shape = info.strides + ndim
for i in range(ndim):
info.strides[i] = PyArray_STRIDES(self)[i]
info.shape[i] = PyArray_DIMS(self)[i]
else:
info.strides = PyArray_STRIDES(self)
info.shape = PyArray_DIMS(self)
info.suboffsets = NULL
info.itemsize = PyArray_ITEMSIZE(self)
info.readonly = not PyArray_ISWRITEABLE(self)
cdef int t
cdef char* f = NULL
cdef dtype descr = self.descr
cdef list stack
cdef int offset
cdef bint hasfields = PyDataType_HASFIELDS(descr)
if not hasfields and not copy_shape:
# do not call releasebuffer
info.obj = None
else:
# need to call releasebuffer
info.obj = self
if not hasfields:
t = descr.type_num
if ((descr.byteorder == '>' and little_endian) or
(descr.byteorder == '<' and not little_endian)):
raise ValueError(u"Non-native byte order not supported")
if t == NPY_BYTE: f = "b"
elif t == NPY_UBYTE: f = "B"
elif t == NPY_SHORT: f = "h"
elif t == NPY_USHORT: f = "H"
elif t == NPY_INT: f = "i"
elif t == NPY_UINT: f = "I"
elif t == NPY_LONG: f = "l"
elif t == NPY_ULONG: f = "L"
elif t == NPY_LONGLONG: f = "q"
elif t == NPY_ULONGLONG: f = "Q"
elif t == NPY_FLOAT: f = "f"
elif t == NPY_DOUBLE: f = "d"
elif t == NPY_LONGDOUBLE: f = "g"
elif t == NPY_CFLOAT: f = "Zf"
elif t == NPY_CDOUBLE: f = "Zd"
elif t == NPY_CLONGDOUBLE: f = "Zg"
elif t == NPY_OBJECT: f = "O"
else:
raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t)
info.format = f
return
else:
info.format = stdlib.malloc(_buffer_format_string_len)
info.format[0] = '^' # Native data types, manual alignment
offset = 0
f = _util_dtypestring(descr, info.format + 1,
info.format + _buffer_format_string_len,
&offset)
f[0] = 0 # Terminate format string
def __releasebuffer__(ndarray self, Py_buffer* info):
if PyArray_HASFIELDS(self):
stdlib.free(info.format)
if sizeof(npy_intp) != sizeof(Py_ssize_t):
stdlib.free(info.strides)
# info.shape was stored after info.strides in the same block
ctypedef signed char npy_bool
ctypedef signed char npy_byte
ctypedef signed short npy_short
ctypedef signed int npy_int
ctypedef signed long npy_long
ctypedef signed long long npy_longlong
ctypedef unsigned char npy_ubyte
ctypedef unsigned short npy_ushort
ctypedef unsigned int npy_uint
ctypedef unsigned long npy_ulong
ctypedef unsigned long long npy_ulonglong
ctypedef float npy_float
ctypedef double npy_double
ctypedef long double npy_longdouble
ctypedef signed char npy_int8
ctypedef signed short npy_int16
ctypedef signed int npy_int32
ctypedef signed long long npy_int64
ctypedef signed long long npy_int96
ctypedef signed long long npy_int128
ctypedef unsigned char npy_uint8
ctypedef unsigned short npy_uint16
ctypedef unsigned int npy_uint32
ctypedef unsigned long long npy_uint64
ctypedef unsigned long long npy_uint96
ctypedef unsigned long long npy_uint128
ctypedef float npy_float32
ctypedef double npy_float64
ctypedef long double npy_float80
ctypedef long double npy_float96
ctypedef long double npy_float128
ctypedef struct npy_cfloat:
double real
double imag
ctypedef struct npy_cdouble:
double real
double imag
ctypedef struct npy_clongdouble:
double real
double imag
ctypedef struct npy_complex64:
double real
double imag
ctypedef struct npy_complex128:
double real
double imag
ctypedef struct npy_complex160:
double real
double imag
ctypedef struct npy_complex192:
double real
double imag
ctypedef struct npy_complex256:
double real
double imag
ctypedef struct PyArray_Dims:
npy_intp *ptr
int len
void import_array()
#
# Macros from ndarrayobject.h
#
bint PyArray_CHKFLAGS(ndarray m, int flags)
bint PyArray_ISCONTIGUOUS(ndarray m)
bint PyArray_ISWRITEABLE(ndarray m)
bint PyArray_ISALIGNED(ndarray m)
int PyArray_NDIM(ndarray)
bint PyArray_ISONESEGMENT(ndarray)
bint PyArray_ISFORTRAN(ndarray)
int PyArray_FORTRANIF(ndarray)
void* PyArray_DATA(ndarray)
char* PyArray_BYTES(ndarray)
npy_intp* PyArray_DIMS(ndarray)
npy_intp* PyArray_STRIDES(ndarray)
npy_intp PyArray_DIM(ndarray, size_t)
npy_intp PyArray_STRIDE(ndarray, size_t)
# object PyArray_BASE(ndarray) wrong refcount semantics
# dtype PyArray_DESCR(ndarray) wrong refcount semantics
int PyArray_FLAGS(ndarray)
npy_intp PyArray_ITEMSIZE(ndarray)
int PyArray_TYPE(ndarray arr)
object PyArray_GETITEM(ndarray arr, void *itemptr)
int PyArray_SETITEM(ndarray arr, void *itemptr, object obj)
bint PyTypeNum_ISBOOL(int)
bint PyTypeNum_ISUNSIGNED(int)
bint PyTypeNum_ISSIGNED(int)
bint PyTypeNum_ISINTEGER(int)
bint PyTypeNum_ISFLOAT(int)
bint PyTypeNum_ISNUMBER(int)
bint PyTypeNum_ISSTRING(int)
bint PyTypeNum_ISCOMPLEX(int)
bint PyTypeNum_ISPYTHON(int)
bint PyTypeNum_ISFLEXIBLE(int)
bint PyTypeNum_ISUSERDEF(int)
bint PyTypeNum_ISEXTENDED(int)
bint PyTypeNum_ISOBJECT(int)
bint PyDataType_ISBOOL(dtype)
bint PyDataType_ISUNSIGNED(dtype)
bint PyDataType_ISSIGNED(dtype)
bint PyDataType_ISINTEGER(dtype)
bint PyDataType_ISFLOAT(dtype)
bint PyDataType_ISNUMBER(dtype)
bint PyDataType_ISSTRING(dtype)
bint PyDataType_ISCOMPLEX(dtype)
bint PyDataType_ISPYTHON(dtype)
bint PyDataType_ISFLEXIBLE(dtype)
bint PyDataType_ISUSERDEF(dtype)
bint PyDataType_ISEXTENDED(dtype)
bint PyDataType_ISOBJECT(dtype)
bint PyDataType_HASFIELDS(dtype)
bint PyArray_ISBOOL(ndarray)
bint PyArray_ISUNSIGNED(ndarray)
bint PyArray_ISSIGNED(ndarray)
bint PyArray_ISINTEGER(ndarray)
bint PyArray_ISFLOAT(ndarray)
bint PyArray_ISNUMBER(ndarray)
bint PyArray_ISSTRING(ndarray)
bint PyArray_ISCOMPLEX(ndarray)
bint PyArray_ISPYTHON(ndarray)
bint PyArray_ISFLEXIBLE(ndarray)
bint PyArray_ISUSERDEF(ndarray)
bint PyArray_ISEXTENDED(ndarray)
bint PyArray_ISOBJECT(ndarray)
bint PyArray_HASFIELDS(ndarray)
bint PyArray_ISVARIABLE(ndarray)
bint PyArray_SAFEALIGNEDCOPY(ndarray)
bint PyArray_ISNBO(ndarray)
bint PyArray_IsNativeByteOrder(ndarray)
bint PyArray_ISNOTSWAPPED(ndarray)
bint PyArray_ISBYTESWAPPED(ndarray)
bint PyArray_FLAGSWAP(ndarray, int)
bint PyArray_ISCARRAY(ndarray)
bint PyArray_ISCARRAY_RO(ndarray)
bint PyArray_ISFARRAY(ndarray)
bint PyArray_ISFARRAY_RO(ndarray)
bint PyArray_ISBEHAVED(ndarray)
bint PyArray_ISBEHAVED_RO(ndarray)
bint PyDataType_ISNOTSWAPPED(dtype)
bint PyDataType_ISBYTESWAPPED(dtype)
bint PyArray_DescrCheck(object)
bint PyArray_Check(object)
bint PyArray_CheckExact(object)
# Cannot be supported due to out arg:
# bint PyArray_HasArrayInterfaceType(object, dtype, object, object&)
# bint PyArray_HasArrayInterface(op, out)
bint PyArray_IsZeroDim(object)
# Cannot be supported due to ## ## in macro:
# bint PyArray_IsScalar(object, verbatim work)
bint PyArray_CheckScalar(object)
bint PyArray_IsPythonNumber(object)
bint PyArray_IsPythonScalar(object)
bint PyArray_IsAnyScalar(object)
bint PyArray_CheckAnyScalar(object)
ndarray PyArray_GETCONTIGUOUS(ndarray)
bint PyArray_SAMESHAPE(ndarray, ndarray)
npy_intp PyArray_SIZE(ndarray)
npy_intp PyArray_NBYTES(ndarray)
object PyArray_FROM_O(object)
object PyArray_FROM_OF(object m, int flags)
bint PyArray_FROM_OT(object m, int type)
bint PyArray_FROM_OTF(object m, int type, int flags)
object PyArray_FROMANY(object m, int type, int min, int max, int flags)
object PyArray_ZEROS(int nd, npy_intp* dims, int type, int fortran)
object PyArray_EMPTY(int nd, npy_intp* dims, int type, int fortran)
void PyArray_FILLWBYTE(object, int val)
npy_intp PyArray_REFCOUNT(object)
object PyArray_ContiguousFromAny(op, int, int min_depth, int max_depth)
unsigned char PyArray_EquivArrTypes(ndarray a1, ndarray a2)
bint PyArray_EquivByteorders(int b1, int b2)
object PyArray_SimpleNew(int nd, npy_intp* dims, int typenum)
object PyArray_SimpleNewFromData(int nd, npy_intp* dims, int typenum, void* data)
#object PyArray_SimpleNewFromDescr(int nd, npy_intp* dims, dtype descr)
object PyArray_ToScalar(void* data, ndarray arr)
void* PyArray_GETPTR1(ndarray m, npy_intp i)
void* PyArray_GETPTR2(ndarray m, npy_intp i, npy_intp j)
void* PyArray_GETPTR3(ndarray m, npy_intp i, npy_intp j, npy_intp k)
void* PyArray_GETPTR4(ndarray m, npy_intp i, npy_intp j, npy_intp k, npy_intp l)
void PyArray_XDECREF_ERR(ndarray)
# Cannot be supported due to out arg
# void PyArray_DESCR_REPLACE(descr)
object PyArray_Copy(ndarray)
object PyArray_FromObject(object op, int type, int min_depth, int max_depth)
object PyArray_ContiguousFromObject(object op, int type, int min_depth, int max_depth)
object PyArray_CopyFromObject(object op, int type, int min_depth, int max_depth)
object PyArray_Cast(ndarray mp, int type_num)
object PyArray_Take(ndarray ap, object items, int axis)
object PyArray_Put(ndarray ap, object items, object values)
void PyArray_ITER_RESET(flatiter it) nogil
void PyArray_ITER_NEXT(flatiter it) nogil
void PyArray_ITER_GOTO(flatiter it, npy_intp* destination) nogil
void PyArray_ITER_GOTO1D(flatiter it, npy_intp ind) nogil
void* PyArray_ITER_DATA(flatiter it) nogil
bint PyArray_ITER_NOTDONE(flatiter it) nogil
void PyArray_MultiIter_RESET(broadcast multi) nogil
void PyArray_MultiIter_NEXT(broadcast multi) nogil
void PyArray_MultiIter_GOTO(broadcast multi, npy_intp dest) nogil
void PyArray_MultiIter_GOTO1D(broadcast multi, npy_intp ind) nogil
void* PyArray_MultiIter_DATA(broadcast multi, npy_intp i) nogil
void PyArray_MultiIter_NEXTi(broadcast multi, npy_intp i) nogil
bint PyArray_MultiIter_NOTDONE(broadcast multi) nogil
# Functions from __multiarray_api.h
# Functions taking dtype and returning object/ndarray are disabled
# for now as they steal dtype references. I'm conservative and disable
# more than is probably needed until it can be checked further.
int PyArray_SetNumericOps (object)
object PyArray_GetNumericOps ()
int PyArray_INCREF (ndarray)
int PyArray_XDECREF (ndarray)
void PyArray_SetStringFunction (object, int)
dtype PyArray_DescrFromType (int)
object PyArray_TypeObjectFromType (int)
char * PyArray_Zero (ndarray)
char * PyArray_One (ndarray)
#object PyArray_CastToType (ndarray, dtype, int)
int PyArray_CastTo (ndarray, ndarray)
int PyArray_CastAnyTo (ndarray, ndarray)
int PyArray_CanCastSafely (int, int)
npy_bool PyArray_CanCastTo (dtype, dtype)
int PyArray_ObjectType (object, int)
dtype PyArray_DescrFromObject (object, dtype)
#ndarray* PyArray_ConvertToCommonType (object, int *)
dtype PyArray_DescrFromScalar (object)
dtype PyArray_DescrFromTypeObject (object)
npy_intp PyArray_Size (object)
#object PyArray_Scalar (void *, dtype, object)
#object PyArray_FromScalar (object, dtype)
void PyArray_ScalarAsCtype (object, void *)
#int PyArray_CastScalarToCtype (object, void *, dtype)
#int PyArray_CastScalarDirect (object, dtype, void *, int)
object PyArray_ScalarFromObject (object)
#PyArray_VectorUnaryFunc * PyArray_GetCastFunc (dtype, int)
object PyArray_FromDims (int, int *, int)
#object PyArray_FromDimsAndDataAndDescr (int, int *, dtype, char *)
#object PyArray_FromAny (object, dtype, int, int, int, object)
object PyArray_EnsureArray (object)
object PyArray_EnsureAnyArray (object)
#object PyArray_FromFile (stdio.FILE *, dtype, npy_intp, char *)
#object PyArray_FromString (char *, npy_intp, dtype, npy_intp, char *)
#object PyArray_FromBuffer (object, dtype, npy_intp, npy_intp)
#object PyArray_FromIter (object, dtype, npy_intp)
object PyArray_Return (ndarray)
#object PyArray_GetField (ndarray, dtype, int)
#int PyArray_SetField (ndarray, dtype, int, object)
object PyArray_Byteswap (ndarray, npy_bool)
object PyArray_Resize (ndarray, PyArray_Dims *, int, NPY_ORDER)
int PyArray_MoveInto (ndarray, ndarray)
int PyArray_CopyInto (ndarray, ndarray)
int PyArray_CopyAnyInto (ndarray, ndarray)
int PyArray_CopyObject (ndarray, object)
object PyArray_NewCopy (ndarray, NPY_ORDER)
object PyArray_ToList (ndarray)
object PyArray_ToString (ndarray, NPY_ORDER)
int PyArray_ToFile (ndarray, stdio.FILE *, char *, char *)
int PyArray_Dump (object, object, int)
object PyArray_Dumps (object, int)
int PyArray_ValidType (int)
void PyArray_UpdateFlags (ndarray, int)
object PyArray_New (type, int, npy_intp *, int, npy_intp *, void *, int, int, object)
#object PyArray_NewFromDescr (type, dtype, int, npy_intp *, npy_intp *, void *, int, object)
#dtype PyArray_DescrNew (dtype)
dtype PyArray_DescrNewFromType (int)
double PyArray_GetPriority (object, double)
object PyArray_IterNew (object)
object PyArray_MultiIterNew (int, ...)
int PyArray_PyIntAsInt (object)
npy_intp PyArray_PyIntAsIntp (object)
int PyArray_Broadcast (broadcast)
void PyArray_FillObjectArray (ndarray, object)
int PyArray_FillWithScalar (ndarray, object)
npy_bool PyArray_CheckStrides (int, int, npy_intp, npy_intp, npy_intp *, npy_intp *)
dtype PyArray_DescrNewByteorder (dtype, char)
object PyArray_IterAllButAxis (object, int *)
#object PyArray_CheckFromAny (object, dtype, int, int, int, object)
#object PyArray_FromArray (ndarray, dtype, int)
object PyArray_FromInterface (object)
object PyArray_FromStructInterface (object)
#object PyArray_FromArrayAttr (object, dtype, object)
#NPY_SCALARKIND PyArray_ScalarKind (int, ndarray*)
int PyArray_CanCoerceScalar (int, int, NPY_SCALARKIND)
object PyArray_NewFlagsObject (object)
npy_bool PyArray_CanCastScalar (type, type)
#int PyArray_CompareUCS4 (npy_ucs4 *, npy_ucs4 *, register size_t)
int PyArray_RemoveSmallest (broadcast)
int PyArray_ElementStrides (object)
void PyArray_Item_INCREF (char *, dtype)
void PyArray_Item_XDECREF (char *, dtype)
object PyArray_FieldNames (object)
object PyArray_Transpose (ndarray, PyArray_Dims *)
object PyArray_TakeFrom (ndarray, object, int, ndarray, NPY_CLIPMODE)
object PyArray_PutTo (ndarray, object, object, NPY_CLIPMODE)
object PyArray_PutMask (ndarray, object, object)
object PyArray_Repeat (ndarray, object, int)
object PyArray_Choose (ndarray, object, ndarray, NPY_CLIPMODE)
int PyArray_Sort (ndarray, int, NPY_SORTKIND)
object PyArray_ArgSort (ndarray, int, NPY_SORTKIND)
object PyArray_SearchSorted (ndarray, object, NPY_SEARCHSIDE)
object PyArray_ArgMax (ndarray, int, ndarray)
object PyArray_ArgMin (ndarray, int, ndarray)
object PyArray_Reshape (ndarray, object)
object PyArray_Newshape (ndarray, PyArray_Dims *, NPY_ORDER)
object PyArray_Squeeze (ndarray)
#object PyArray_View (ndarray, dtype, type)
object PyArray_SwapAxes (ndarray, int, int)
object PyArray_Max (ndarray, int, ndarray)
object PyArray_Min (ndarray, int, ndarray)
object PyArray_Ptp (ndarray, int, ndarray)
object PyArray_Mean (ndarray, int, int, ndarray)
object PyArray_Trace (ndarray, int, int, int, int, ndarray)
object PyArray_Diagonal (ndarray, int, int, int)
object PyArray_Clip (ndarray, object, object, ndarray)
object PyArray_Conjugate (ndarray, ndarray)
object PyArray_Nonzero (ndarray)
object PyArray_Std (ndarray, int, int, ndarray, int)
object PyArray_Sum (ndarray, int, int, ndarray)
object PyArray_CumSum (ndarray, int, int, ndarray)
object PyArray_Prod (ndarray, int, int, ndarray)
object PyArray_CumProd (ndarray, int, int, ndarray)
object PyArray_All (ndarray, int, ndarray)
object PyArray_Any (ndarray, int, ndarray)
object PyArray_Compress (ndarray, object, int, ndarray)
object PyArray_Flatten (ndarray, NPY_ORDER)
object PyArray_Ravel (ndarray, NPY_ORDER)
npy_intp PyArray_MultiplyList (npy_intp *, int)
int PyArray_MultiplyIntList (int *, int)
void * PyArray_GetPtr (ndarray, npy_intp*)
int PyArray_CompareLists (npy_intp *, npy_intp *, int)
#int PyArray_AsCArray (object*, void *, npy_intp *, int, dtype)
#int PyArray_As1D (object*, char **, int *, int)
#int PyArray_As2D (object*, char ***, int *, int *, int)
int PyArray_Free (object, void *)
#int PyArray_Converter (object, object*)
int PyArray_IntpFromSequence (object, npy_intp *, int)
object PyArray_Concatenate (object, int)
object PyArray_InnerProduct (object, object)
object PyArray_MatrixProduct (object, object)
object PyArray_CopyAndTranspose (object)
object PyArray_Correlate (object, object, int)
int PyArray_TypestrConvert (int, int)
#int PyArray_DescrConverter (object, dtype*)
#int PyArray_DescrConverter2 (object, dtype*)
int PyArray_IntpConverter (object, PyArray_Dims *)
#int PyArray_BufferConverter (object, chunk)
int PyArray_AxisConverter (object, int *)
int PyArray_BoolConverter (object, npy_bool *)
int PyArray_ByteorderConverter (object, char *)
int PyArray_OrderConverter (object, NPY_ORDER *)
unsigned char PyArray_EquivTypes (dtype, dtype)
#object PyArray_Zeros (int, npy_intp *, dtype, int)
#object PyArray_Empty (int, npy_intp *, dtype, int)
object PyArray_Where (object, object, object)
object PyArray_Arange (double, double, double, int)
#object PyArray_ArangeObj (object, object, object, dtype)
int PyArray_SortkindConverter (object, NPY_SORTKIND *)
object PyArray_LexSort (object, int)
object PyArray_Round (ndarray, int, ndarray)
unsigned char PyArray_EquivTypenums (int, int)
int PyArray_RegisterDataType (dtype)
int PyArray_RegisterCastFunc (dtype, int, PyArray_VectorUnaryFunc *)
int PyArray_RegisterCanCast (dtype, int, NPY_SCALARKIND)
#void PyArray_InitArrFuncs (PyArray_ArrFuncs *)
object PyArray_IntTupleFromIntp (int, npy_intp *)
int PyArray_TypeNumFromName (char *)
int PyArray_ClipmodeConverter (object, NPY_CLIPMODE *)
#int PyArray_OutputConverter (object, ndarray*)
object PyArray_BroadcastToShape (object, npy_intp *, int)
void _PyArray_SigintHandler (int)
void* _PyArray_GetSigintBuf ()
#int PyArray_DescrAlignConverter (object, dtype*)
#int PyArray_DescrAlignConverter2 (object, dtype*)
int PyArray_SearchsideConverter (object, void *)
object PyArray_CheckAxis (ndarray, int *, int)
npy_intp PyArray_OverflowMultiplyList (npy_intp *, int)
int PyArray_CompareString (char *, char *, size_t)
# Typedefs that matches the runtime dtype objects in
# the numpy module.
# The ones that are commented out needs an IFDEF function
# in Cython to enable them only on the right systems.
ctypedef npy_int8 int8_t
ctypedef npy_int16 int16_t
ctypedef npy_int32 int32_t
ctypedef npy_int64 int64_t
#ctypedef npy_int96 int96_t
#ctypedef npy_int128 int128_t
ctypedef npy_uint8 uint8_t
ctypedef npy_uint16 uint16_t
ctypedef npy_uint32 uint32_t
ctypedef npy_uint64 uint64_t
#ctypedef npy_uint96 uint96_t
#ctypedef npy_uint128 uint128_t
ctypedef npy_float32 float32_t
ctypedef npy_float64 float64_t
#ctypedef npy_float80 float80_t
#ctypedef npy_float128 float128_t
ctypedef float complex complex64_t
ctypedef double complex complex128_t
# The int types are mapped a bit surprising --
# numpy.int corresponds to 'l' and numpy.long to 'q'
ctypedef npy_long int_t
ctypedef npy_longlong long_t
ctypedef npy_intp intp_t
ctypedef npy_uintp uintp_t
ctypedef npy_ulong uint_t
ctypedef npy_ulonglong ulong_t
ctypedef npy_double float_t
ctypedef npy_double double_t
ctypedef npy_longdouble longdouble_t
ctypedef npy_cfloat cfloat_t
ctypedef npy_cdouble cdouble_t
ctypedef npy_clongdouble clongdouble_t
ctypedef npy_cdouble complex_t
cdef inline object PyArray_MultiIterNew1(a):
return PyArray_MultiIterNew(1, a)
cdef inline object PyArray_MultiIterNew2(a, b):
return PyArray_MultiIterNew(2, a, b)
cdef inline object PyArray_MultiIterNew3(a, b, c):
return PyArray_MultiIterNew(3, a, b, c)
cdef inline object PyArray_MultiIterNew4(a, b, c, d):
return PyArray_MultiIterNew(4, a, b, c, d)
cdef inline object PyArray_MultiIterNew5(a, b, c, d, e):
return PyArray_MultiIterNew(5, a, b, c, d, e)
cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL:
# Recursive utility function used in __getbuffer__ to get format
# string. The new location in the format string is returned.
cdef dtype child
cdef int delta_offset
cdef tuple i
cdef int endian_detector = 1
cdef bint little_endian = ((&endian_detector)[0] != 0)
cdef tuple fields
for childname in descr.names:
fields = descr.fields[childname]
child, new_offset = fields
if (end - f) - (new_offset - offset[0]) < 15:
raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd")
if ((child.byteorder == '>' and little_endian) or
(child.byteorder == '<' and not little_endian)):
raise ValueError(u"Non-native byte order not supported")
# One could encode it in the format string and have Cython
# complain instead, BUT: < and > in format strings also imply
# standardized sizes for datatypes, and we rely on native in
# order to avoid reencoding data types based on their size.
#
# A proper PEP 3118 exporter for other clients than Cython
# must deal properly with this!
# Output padding bytes
while offset[0] < new_offset:
f[0] = 120 # "x"; pad byte
f += 1
offset[0] += 1
offset[0] += child.itemsize
if not PyDataType_HASFIELDS(child):
t = child.type_num
if end - f < 5:
raise RuntimeError(u"Format string allocated too short.")
# Until ticket #99 is fixed, use integers to avoid warnings
if t == NPY_BYTE: f[0] = 98 #"b"
elif t == NPY_UBYTE: f[0] = 66 #"B"
elif t == NPY_SHORT: f[0] = 104 #"h"
elif t == NPY_USHORT: f[0] = 72 #"H"
elif t == NPY_INT: f[0] = 105 #"i"
elif t == NPY_UINT: f[0] = 73 #"I"
elif t == NPY_LONG: f[0] = 108 #"l"
elif t == NPY_ULONG: f[0] = 76 #"L"
elif t == NPY_LONGLONG: f[0] = 113 #"q"
elif t == NPY_ULONGLONG: f[0] = 81 #"Q"
elif t == NPY_FLOAT: f[0] = 102 #"f"
elif t == NPY_DOUBLE: f[0] = 100 #"d"
elif t == NPY_LONGDOUBLE: f[0] = 103 #"g"
elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf
elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd
elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg
elif t == NPY_OBJECT: f[0] = 79 #"O"
else:
raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t)
f += 1
else:
# Cython ignores struct boundary information ("T{...}"),
# so don't output it
f = _util_dtypestring(child, f, end, offset)
return f
#
# ufunc API
#
cdef extern from "numpy/ufuncobject.h":
ctypedef void (*PyUFuncGenericFunction) (char **, npy_intp *, npy_intp *, void *)
ctypedef extern class numpy.ufunc [object PyUFuncObject]:
cdef:
int nin, nout, nargs
int identity
PyUFuncGenericFunction *functions
void **data
int ntypes
int check_return
char *name, *types
char *doc
void *ptr
PyObject *obj
PyObject *userloops
cdef enum:
PyUFunc_Zero
PyUFunc_One
PyUFunc_None
UFUNC_ERR_IGNORE
UFUNC_ERR_WARN
UFUNC_ERR_RAISE
UFUNC_ERR_CALL
UFUNC_ERR_PRINT
UFUNC_ERR_LOG
UFUNC_MASK_DIVIDEBYZERO
UFUNC_MASK_OVERFLOW
UFUNC_MASK_UNDERFLOW
UFUNC_MASK_INVALID
UFUNC_SHIFT_DIVIDEBYZERO
UFUNC_SHIFT_OVERFLOW
UFUNC_SHIFT_UNDERFLOW
UFUNC_SHIFT_INVALID
UFUNC_FPE_DIVIDEBYZERO
UFUNC_FPE_OVERFLOW
UFUNC_FPE_UNDERFLOW
UFUNC_FPE_INVALID
UFUNC_ERR_DEFAULT
UFUNC_ERR_DEFAULT2
object PyUFunc_FromFuncAndData(PyUFuncGenericFunction *,
void **, char *, int, int, int, int, char *, char *, int)
int PyUFunc_RegisterLoopForType(ufunc, int,
PyUFuncGenericFunction, int *, void *)
int PyUFunc_GenericFunction \
(ufunc, PyObject *, PyObject *, PyArrayObject **)
void PyUFunc_f_f_As_d_d \
(char **, npy_intp *, npy_intp *, void *)
void PyUFunc_d_d \
(char **, npy_intp *, npy_intp *, void *)
void PyUFunc_f_f \
(char **, npy_intp *, npy_intp *, void *)
void PyUFunc_g_g \
(char **, npy_intp *, npy_intp *, void *)
void PyUFunc_F_F_As_D_D \
(char **, npy_intp *, npy_intp *, void *)
void PyUFunc_F_F \
(char **, npy_intp *, npy_intp *, void *)
void PyUFunc_D_D \
(char **, npy_intp *, npy_intp *, void *)
void PyUFunc_G_G \
(char **, npy_intp *, npy_intp *, void *)
void PyUFunc_O_O \
(char **, npy_intp *, npy_intp *, void *)
void PyUFunc_ff_f_As_dd_d \
(char **, npy_intp *, npy_intp *, void *)
void PyUFunc_ff_f \
(char **, npy_intp *, npy_intp *, void *)
void PyUFunc_dd_d \
(char **, npy_intp *, npy_intp *, void *)
void PyUFunc_gg_g \
(char **, npy_intp *, npy_intp *, void *)
void PyUFunc_FF_F_As_DD_D \
(char **, npy_intp *, npy_intp *, void *)
void PyUFunc_DD_D \
(char **, npy_intp *, npy_intp *, void *)
void PyUFunc_FF_F \
(char **, npy_intp *, npy_intp *, void *)
void PyUFunc_GG_G \
(char **, npy_intp *, npy_intp *, void *)
void PyUFunc_OO_O \
(char **, npy_intp *, npy_intp *, void *)
void PyUFunc_O_O_method \
(char **, npy_intp *, npy_intp *, void *)
void PyUFunc_OO_O_method \
(char **, npy_intp *, npy_intp *, void *)
void PyUFunc_On_Om \
(char **, npy_intp *, npy_intp *, void *)
int PyUFunc_GetPyValues \
(char *, int *, int *, PyObject **)
int PyUFunc_checkfperr \
(int, PyObject *, int *)
void PyUFunc_clearfperr()
int PyUFunc_getfperr()
int PyUFunc_handlefperr \
(int, PyObject *, int, int *)
int PyUFunc_ReplaceLoopBySignature \
(ufunc, PyUFuncGenericFunction, int *, PyUFuncGenericFunction *)
object PyUFunc_FromFuncAndDataAndSignature \
(PyUFuncGenericFunction *, void **, char *, int, int, int,
int, char *, char *, int, char *)
void import_ufunc()
cdef inline void set_array_base(ndarray arr, object base):
cdef PyObject* baseptr
if base is None:
baseptr = NULL
else:
Py_INCREF(base) # important to do this before decref below!
baseptr = base
Py_XDECREF(arr.base)
arr.base = baseptr
cdef inline object get_array_base(ndarray arr):
if arr.base is NULL:
return None
else:
return arr.base
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/posix/ 0000775 0000000 0000000 00000000000 11446142532 0024120 5 ustar 00root root 0000000 0000000 cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/posix/__init__.pxd 0000664 0000000 0000000 00000000015 11446142532 0026370 0 ustar 00root root 0000000 0000000 # empty file
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/posix/fcntl.pxd 0000664 0000000 0000000 00000002231 11446142532 0025741 0 ustar 00root root 0000000 0000000 # http://www.opengroup.org/onlinepubs/009695399/basedefs/fcntl.h.html
cdef extern from "fcntl.h" nogil:
enum: F_DUPFD
enum: F_GETFD
enum: F_SETFD
enum: F_GETFL
enum: F_SETFL
enum: F_GETLK
enum: F_SETLK
enum: F_SETLKW
enum: F_GETOWN
enum: F_SETOWN
enum: FD_CLOEXEC
enum: F_RDLCK
enum: F_UNLCK
enum: F_WRLCK
enum: SEEK_SET
enum: SEEK_CUR
enum: SEEK_END
enum: O_CREAT
enum: O_EXCL
enum: O_NOCTTY
enum: O_TRUNC
enum: O_APPEND
enum: O_DSYNC
enum: O_NONBLOCK
enum: O_RSYNC
enum: O_SYNC
enum: O_ACCMODE # O_RDONLY|O_WRONLY|O_RDWR
enum: O_RDONLY
enum: O_WRONLY
enum: O_RDWR
enum: S_IFMT
enum: S_IFBLK
enum: S_IFCHR
enum: S_IFIFO
enum: S_IFREG
enum: S_IFDIR
enum: S_IFLNK
enum: S_IFSOCK
ctypedef int mode_t
ctypedef signed pid_t
ctypedef signed off_t
struct flock:
short l_type
short l_whence
off_t l_start
off_t l_len
pid_t l_pid
int creat(char *, mode_t)
int fcntl(int, int, ...)
int open(char *, int, ...)
#int open (char *, int, mode_t)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Includes/posix/unistd.pxd 0000664 0000000 0000000 00000007145 11446142532 0026152 0 ustar 00root root 0000000 0000000 # http://www.opengroup.org/onlinepubs/009695399/basedefs/unistd.h.html
cdef extern from "unistd.h" nogil:
#:NULL
enum: R_OK
enum: W_OK
enum: X_OK
enum: F_OK
# confstr()
#_CS_PATH
#_CS_POSIX_*
enum: SEEK_SET
enum: SEEK_CUR
enum: SEEK_END
enum: F_LOCK
enum: F_TEST
enum: F_TLOCK
enum: F_ULOCK
# pathconf()
# _PC_*
# sysconf()
# _SC_*
enum: STDIN_FILENO #0
enum: STDOUT_FILENO #1
enum: STDERR_FILENO #2
#:ctypedef unsigned size_t
#:ctypedef signed ssize_t
ctypedef int uid_t
ctypedef int gid_t
ctypedef signed off_t
ctypedef signed pid_t
ctypedef unsigned useconds_t
ctypedef signed intptr_t
int access(char *, int)
unsigned alarm(unsigned)
int chdir(char *)
int chown(char *, uid_t, gid_t)
int close(int)
size_t confstr(int, char *, size_t)
char *crypt(char *, char *)
char *ctermid(char *)
int dup(int)
int dup2(int, int)
void encrypt(char[64], int)
int execl(char *, char *, ...)
int execle(char *, char *, ...)
int execlp(char *, char *, ...)
int execv(char *, char *[])
int execve(char *, char *[], char *[])
int execvp(char *, char *[])
void _exit(int)
int fchown(int, uid_t, gid_t)
int fchdir(int)
int fdatasync(int)
pid_t fork()
long fpathconf(int, int)
int fsync(int)
int ftruncate(int, off_t)
char *getcwd(char *, size_t)
gid_t getegid()
uid_t geteuid()
gid_t getgid()
int getgroups(int, gid_t [])
long gethostid()
int gethostname(char *, size_t)
char *getlogin()
int getlogin_r(char *, size_t)
int getopt(int, char * [], char *)
pid_t getpgid(pid_t)
pid_t getpgrp()
pid_t getpid()
pid_t getppid()
pid_t getsid(pid_t)
uid_t getuid()
char *getwd(char *)
int isatty(int)
int lchown(char *, uid_t, gid_t)
int link(char *, char *)
int lockf(int, int, off_t)
off_t lseek(int, off_t, int)
int nice(int)
long pathconf(char *, int)
int pause()
int pipe(int [2])
ssize_t pread(int, void *, size_t, off_t)
ssize_t pwrite(int, void *, size_t, off_t)
ssize_t read(int, void *, size_t)
ssize_t readlink(char *, char *, size_t)
int rmdir(char *)
int setegid(gid_t)
int seteuid(uid_t)
int setgid(gid_t)
int setpgid(pid_t, pid_t)
pid_t setpgrp()
int setregid(gid_t, gid_t)
int setreuid(uid_t, uid_t)
pid_t setsid()
int setuid(uid_t)
unsigned sleep(unsigned)
void swab(void *, void *, ssize_t)
int symlink(char *, char *)
void sync()
long sysconf(int)
pid_t tcgetpgrp(int)
int tcsetpgrp(int, pid_t)
int truncate(char *, off_t)
char *ttyname(int)
int ttyname_r(int, char *, size_t)
useconds_t ualarm(useconds_t, useconds_t)
int unlink(char *)
int usleep(useconds_t)
pid_t vfork()
ssize_t write(int, void *, size_t)
char *optarg
int optind
int opterr
int optopt
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Plex/ 0000775 0000000 0000000 00000000000 11446142532 0022120 5 ustar 00root root 0000000 0000000 cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Plex/Actions.py 0000664 0000000 0000000 00000004464 11446142532 0024102 0 ustar 00root root 0000000 0000000 #=======================================================================
#
# Python Lexical Analyser
#
# Actions for use in token specifications
#
#=======================================================================
class Action(object):
def same_as(self, other):
return self is other
class Return(Action):
"""
Internal Plex action which causes |value| to
be returned as the value of the associated token
"""
value = None
def __init__(self, value):
self.value = value
def perform(self, token_stream, text):
return self.value
def same_as(self, other):
return isinstance(other, Return) and self.value == other.value
def __repr__(self):
return "Return(%s)" % repr(self.value)
class Call(Action):
"""
Internal Plex action which causes a function to be called.
"""
function = None
def __init__(self, function):
self.function = function
def perform(self, token_stream, text):
return self.function(token_stream, text)
def __repr__(self):
return "Call(%s)" % self.function.__name__
def same_as(self, other):
return isinstance(other, Call) and self.function is other.function
class Begin(Action):
"""
Begin(state_name) is a Plex action which causes the Scanner to
enter the state |state_name|. See the docstring of Plex.Lexicon
for more information.
"""
state_name = None
def __init__(self, state_name):
self.state_name = state_name
def perform(self, token_stream, text):
token_stream.begin(self.state_name)
def __repr__(self):
return "Begin(%s)" % self.state_name
def same_as(self, other):
return isinstance(other, Begin) and self.state_name == other.state_name
class Ignore(Action):
"""
IGNORE is a Plex action which causes its associated token
to be ignored. See the docstring of Plex.Lexicon for more
information.
"""
def perform(self, token_stream, text):
return None
def __repr__(self):
return "IGNORE"
IGNORE = Ignore()
IGNORE.__doc__ = Ignore.__doc__
class Text(Action):
"""
TEXT is a Plex action which causes the text of a token to
be returned as the value of the token. See the docstring of
Plex.Lexicon for more information.
"""
def perform(self, token_stream, text):
return text
def __repr__(self):
return "TEXT"
TEXT = Text()
TEXT.__doc__ = Text.__doc__
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Plex/DFA.py 0000664 0000000 0000000 00000012634 11446142532 0023072 0 ustar 00root root 0000000 0000000 #=======================================================================
#
# Python Lexical Analyser
#
# Converting NFA to DFA
#
#=======================================================================
import Machines
from Machines import LOWEST_PRIORITY
from Transitions import TransitionMap
def nfa_to_dfa(old_machine, debug = None):
"""
Given a nondeterministic Machine, return a new equivalent
Machine which is deterministic.
"""
# We build a new machine whose states correspond to sets of states
# in the old machine. Initially we add a new state corresponding to
# the epsilon-closure of each initial old state. Then we give transitions
# to each new state which are the union of all transitions out of any
# of the corresponding old states. The new state reached on a given
# character is the one corresponding to the set of states reachable
# on that character from any of the old states. As new combinations of
# old states are created, new states are added as needed until closure
# is reached.
new_machine = Machines.FastMachine()
state_map = StateMap(new_machine)
# Seed the process using the initial states of the old machine.
# Make the corresponding new states into initial states of the new
# machine with the same names.
for (key, old_state) in old_machine.initial_states.iteritems():
new_state = state_map.old_to_new(epsilon_closure(old_state))
new_machine.make_initial_state(key, new_state)
# Tricky bit here: we add things to the end of this list while we're
# iterating over it. The iteration stops when closure is achieved.
for new_state in new_machine.states:
transitions = TransitionMap()
for old_state in state_map.new_to_old(new_state):
for event, old_target_states in old_state.transitions.iteritems():
if event and old_target_states:
transitions.add_set(event, set_epsilon_closure(old_target_states))
for event, old_states in transitions.iteritems():
new_machine.add_transitions(new_state, event, state_map.old_to_new(old_states))
if debug:
debug.write("\n===== State Mapping =====\n")
state_map.dump(debug)
return new_machine
def set_epsilon_closure(state_set):
"""
Given a set of states, return the union of the epsilon
closures of its member states.
"""
result = {}
for state1 in state_set:
for state2 in epsilon_closure(state1):
result[state2] = 1
return result
def epsilon_closure(state):
"""
Return the set of states reachable from the given state
by epsilon moves.
"""
# Cache the result
result = state.epsilon_closure
if result is None:
result = {}
state.epsilon_closure = result
add_to_epsilon_closure(result, state)
return result
def add_to_epsilon_closure(state_set, state):
"""
Recursively add to |state_set| states reachable from the given state
by epsilon moves.
"""
if not state_set.get(state, 0):
state_set[state] = 1
state_set_2 = state.transitions.get_epsilon()
if state_set_2:
for state2 in state_set_2:
add_to_epsilon_closure(state_set, state2)
class StateMap(object):
"""
Helper class used by nfa_to_dfa() to map back and forth between
sets of states from the old machine and states of the new machine.
"""
new_machine = None # Machine
old_to_new_dict = None # {(old_state,...) : new_state}
new_to_old_dict = None # {id(new_state) : old_state_set}
def __init__(self, new_machine):
self.new_machine = new_machine
self.old_to_new_dict = {}
self.new_to_old_dict= {}
def old_to_new(self, old_state_set):
"""
Return the state of the new machine corresponding to the
set of old machine states represented by |state_set|. A new
state will be created if necessary. If any of the old states
are accepting states, the new state will be an accepting state
with the highest priority action from the old states.
"""
key = self.make_key(old_state_set)
new_state = self.old_to_new_dict.get(key, None)
if not new_state:
action = self.highest_priority_action(old_state_set)
new_state = self.new_machine.new_state(action)
self.old_to_new_dict[key] = new_state
self.new_to_old_dict[id(new_state)] = old_state_set
#for old_state in old_state_set.keys():
#new_state.merge_actions(old_state)
return new_state
def highest_priority_action(self, state_set):
best_action = None
best_priority = LOWEST_PRIORITY
for state in state_set:
priority = state.action_priority
if priority > best_priority:
best_action = state.action
best_priority = priority
return best_action
# def old_to_new_set(self, old_state_set):
# """
# Return the new state corresponding to a set of old states as
# a singleton set.
# """
# return {self.old_to_new(old_state_set):1}
def new_to_old(self, new_state):
"""Given a new state, return a set of corresponding old states."""
return self.new_to_old_dict[id(new_state)]
def make_key(self, state_set):
"""
Convert a set of states into a uniquified
sorted tuple suitable for use as a dictionary key.
"""
lst = list(state_set)
lst.sort()
return tuple(lst)
def dump(self, file):
from Transitions import state_set_str
for new_state in self.new_machine.states:
old_state_set = self.new_to_old_dict[id(new_state)]
file.write(" State %s <-- %s\n" % (
new_state['number'], state_set_str(old_state_set)))
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Plex/Errors.py 0000664 0000000 0000000 00000002135 11446142532 0023747 0 ustar 00root root 0000000 0000000 #=======================================================================
#
# Python Lexical Analyser
#
# Exception classes
#
#=======================================================================
class PlexError(Exception):
message = ""
class PlexTypeError(PlexError, TypeError):
pass
class PlexValueError(PlexError, ValueError):
pass
class InvalidRegex(PlexError):
pass
class InvalidToken(PlexError):
def __init__(self, token_number, message):
PlexError.__init__(self, "Token number %d: %s" % (token_number, message))
class InvalidScanner(PlexError):
pass
class AmbiguousAction(PlexError):
message = "Two tokens with different actions can match the same string"
def __init__(self):
pass
class UnrecognizedInput(PlexError):
scanner = None
position = None
state_name = None
def __init__(self, scanner, state_name):
self.scanner = scanner
self.position = scanner.position()
self.state_name = state_name
def __str__(self):
return ("'%s', line %d, char %d: Token not recognised in state %s"
% (self.position + (repr(self.state_name),)))
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Plex/Lexicons.py 0000664 0000000 0000000 00000014224 11446142532 0024261 0 ustar 00root root 0000000 0000000 #=======================================================================
#
# Python Lexical Analyser
#
# Lexical Analyser Specification
#
#=======================================================================
import types
import Actions
import DFA
import Errors
import Machines
import Regexps
# debug_flags for Lexicon constructor
DUMP_NFA = 1
DUMP_DFA = 2
class State(object):
"""
This class is used as part of a Plex.Lexicon specification to
introduce a user-defined state.
Constructor:
State(name, token_specifications)
"""
name = None
tokens = None
def __init__(self, name, tokens):
self.name = name
self.tokens = tokens
class Lexicon(object):
"""
Lexicon(specification) builds a lexical analyser from the given
|specification|. The specification consists of a list of
specification items. Each specification item may be either:
1) A token definition, which is a tuple:
(pattern, action)
The |pattern| is a regular axpression built using the
constructors defined in the Plex module.
The |action| is the action to be performed when this pattern
is recognised (see below).
2) A state definition:
State(name, tokens)
where |name| is a character string naming the state,
and |tokens| is a list of token definitions as
above. The meaning and usage of states is described
below.
Actions
-------
The |action| in a token specication may be one of three things:
1) A function, which is called as follows:
function(scanner, text)
where |scanner| is the relevant Scanner instance, and |text|
is the matched text. If the function returns anything
other than None, that value is returned as the value of the
token. If it returns None, scanning continues as if the IGNORE
action were specified (see below).
2) One of the following special actions:
IGNORE means that the recognised characters will be treated as
white space and ignored. Scanning will continue until
the next non-ignored token is recognised before returning.
TEXT causes the scanned text itself to be returned as the
value of the token.
3) Any other value, which is returned as the value of the token.
States
------
At any given time, the scanner is in one of a number of states.
Associated with each state is a set of possible tokens. When scanning,
only tokens associated with the current state are recognised.
There is a default state, whose name is the empty string. Token
definitions which are not inside any State definition belong to
the default state.
The initial state of the scanner is the default state. The state can
be changed in one of two ways:
1) Using Begin(state_name) as the action of a token.
2) Calling the begin(state_name) method of the Scanner.
To change back to the default state, use '' as the state name.
"""
machine = None # Machine
tables = None # StateTableMachine
def __init__(self, specifications, debug = None, debug_flags = 7, timings = None):
if type(specifications) != types.ListType:
raise Errors.InvalidScanner("Scanner definition is not a list")
if timings:
from Timing import time
total_time = 0.0
time1 = time()
nfa = Machines.Machine()
default_initial_state = nfa.new_initial_state('')
token_number = 1
for spec in specifications:
if isinstance(spec, State):
user_initial_state = nfa.new_initial_state(spec.name)
for token in spec.tokens:
self.add_token_to_machine(
nfa, user_initial_state, token, token_number)
token_number = token_number + 1
elif type(spec) == types.TupleType:
self.add_token_to_machine(
nfa, default_initial_state, spec, token_number)
token_number = token_number + 1
else:
raise Errors.InvalidToken(
token_number,
"Expected a token definition (tuple) or State instance")
if timings:
time2 = time()
total_time = total_time + (time2 - time1)
time3 = time()
if debug and (debug_flags & 1):
debug.write("\n============= NFA ===========\n")
nfa.dump(debug)
dfa = DFA.nfa_to_dfa(nfa, debug = (debug_flags & 3) == 3 and debug)
if timings:
time4 = time()
total_time = total_time + (time4 - time3)
if debug and (debug_flags & 2):
debug.write("\n============= DFA ===========\n")
dfa.dump(debug)
if timings:
timings.write("Constructing NFA : %5.2f\n" % (time2 - time1))
timings.write("Converting to DFA: %5.2f\n" % (time4 - time3))
timings.write("TOTAL : %5.2f\n" % total_time)
self.machine = dfa
def add_token_to_machine(self, machine, initial_state, token_spec, token_number):
try:
(re, action_spec) = self.parse_token_definition(token_spec)
# Disabled this -- matching empty strings can be useful
#if re.nullable:
# raise Errors.InvalidToken(
# token_number, "Pattern can match 0 input symbols")
if isinstance(action_spec, Actions.Action):
action = action_spec
else:
try:
action_spec.__call__
except AttributeError:
action = Actions.Return(action_spec)
else:
action = Actions.Call(action_spec)
final_state = machine.new_state()
re.build_machine(machine, initial_state, final_state,
match_bol = 1, nocase = 0)
final_state.set_action(action, priority = -token_number)
except Errors.PlexError, e:
raise e.__class__("Token number %d: %s" % (token_number, e))
def parse_token_definition(self, token_spec):
if type(token_spec) != types.TupleType:
raise Errors.InvalidToken("Token definition is not a tuple")
if len(token_spec) != 2:
raise Errors.InvalidToken("Wrong number of items in token definition")
pattern, action = token_spec
if not isinstance(pattern, Regexps.RE):
raise Errors.InvalidToken("Pattern is not an RE instance")
return (pattern, action)
def get_initial_state(self, name):
return self.machine.get_initial_state(name)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Plex/Machines.py 0000664 0000000 0000000 00000016553 11446142532 0024233 0 ustar 00root root 0000000 0000000 #=======================================================================
#
# Python Lexical Analyser
#
# Classes for building NFAs and DFAs
#
#=======================================================================
import sys
from Transitions import TransitionMap
LOWEST_PRIORITY = -sys.maxint
class Machine(object):
"""A collection of Nodes representing an NFA or DFA."""
states = None # [Node]
next_state_number = 1
initial_states = None # {(name, bol): Node}
def __init__(self):
self.states = []
self.initial_states = {}
def __del__(self):
#print "Destroying", self ###
for state in self.states:
state.destroy()
def new_state(self):
"""Add a new state to the machine and return it."""
s = Node()
n = self.next_state_number
self.next_state_number = n + 1
s.number = n
self.states.append(s)
return s
def new_initial_state(self, name):
state = self.new_state()
self.make_initial_state(name, state)
return state
def make_initial_state(self, name, state):
self.initial_states[name] = state
def get_initial_state(self, name):
return self.initial_states[name]
def dump(self, file):
file.write("Plex.Machine:\n")
if self.initial_states is not None:
file.write(" Initial states:\n")
for (name, state) in self.initial_states.iteritems():
file.write(" '%s': %d\n" % (name, state.number))
for s in self.states:
s.dump(file)
class Node(object):
"""A state of an NFA or DFA."""
transitions = None # TransitionMap
action = None # Action
action_priority = None # integer
number = 0 # for debug output
epsilon_closure = None # used by nfa_to_dfa()
def __init__(self):
# Preinitialise the list of empty transitions, because
# the nfa-to-dfa algorithm needs it
#self.transitions = {'':[]}
self.transitions = TransitionMap()
self.action_priority = LOWEST_PRIORITY
def destroy(self):
#print "Destroying", self ###
self.transitions = None
self.action = None
self.epsilon_closure = None
def add_transition(self, event, new_state):
self.transitions.add(event, new_state)
def link_to(self, state):
"""Add an epsilon-move from this state to another state."""
self.add_transition('', state)
def set_action(self, action, priority):
"""Make this an accepting state with the given action. If
there is already an action, choose the action with highest
priority."""
if priority > self.action_priority:
self.action = action
self.action_priority = priority
def get_action(self):
return self.action
def get_action_priority(self):
return self.action_priority
def is_accepting(self):
return self.action is not None
def __str__(self):
return "State %d" % self.number
def dump(self, file):
# Header
file.write(" State %d:\n" % self.number)
# Transitions
# self.dump_transitions(file)
self.transitions.dump(file)
# Action
action = self.action
priority = self.action_priority
if action is not None:
file.write(" %s [priority %d]\n" % (action, priority))
def __lt__(self, other):
return self.number < other.number
class FastMachine(object):
"""
FastMachine is a deterministic machine represented in a way that
allows fast scanning.
"""
initial_states = None # {state_name:state}
states = None # [state]
# where state = {event:state, 'else':state, 'action':Action}
next_number = 1 # for debugging
new_state_template = {
'':None, 'bol':None, 'eol':None, 'eof':None, 'else':None
}
def __init__(self, old_machine = None):
self.initial_states = initial_states = {}
self.states = []
if old_machine:
self.old_to_new = old_to_new = {}
for old_state in old_machine.states:
new_state = self.new_state()
old_to_new[old_state] = new_state
for name, old_state in old_machine.initial_states.iteritems():
initial_states[name] = old_to_new[old_state]
for old_state in old_machine.states:
new_state = old_to_new[old_state]
for event, old_state_set in old_state.transitions.iteritems():
if old_state_set:
new_state[event] = old_to_new[old_state_set.keys()[0]]
else:
new_state[event] = None
new_state['action'] = old_state.action
def __del__(self):
for state in self.states:
state.clear()
def new_state(self, action = None):
number = self.next_number
self.next_number = number + 1
result = self.new_state_template.copy()
result['number'] = number
result['action'] = action
self.states.append(result)
return result
def make_initial_state(self, name, state):
self.initial_states[name] = state
def add_transitions(self, state, event, new_state, maxint=sys.maxint):
if type(event) is tuple:
code0, code1 = event
if code0 == -maxint:
state['else'] = new_state
elif code1 != maxint:
while code0 < code1:
state[chr(code0)] = new_state
code0 = code0 + 1
else:
state[event] = new_state
def get_initial_state(self, name):
return self.initial_states[name]
def dump(self, file):
file.write("Plex.FastMachine:\n")
file.write(" Initial states:\n")
for name, state in self.initial_states.iteritems():
file.write(" %s: %s\n" % (repr(name), state['number']))
for state in self.states:
self.dump_state(state, file)
def dump_state(self, state, file):
# Header
file.write(" State %d:\n" % state['number'])
# Transitions
self.dump_transitions(state, file)
# Action
action = state['action']
if action is not None:
file.write(" %s\n" % action)
def dump_transitions(self, state, file):
chars_leading_to_state = {}
special_to_state = {}
for (c, s) in state.iteritems():
if len(c) == 1:
chars = chars_leading_to_state.get(id(s), None)
if chars is None:
chars = []
chars_leading_to_state[id(s)] = chars
chars.append(c)
elif len(c) <= 4:
special_to_state[c] = s
ranges_to_state = {}
for state in self.states:
char_list = chars_leading_to_state.get(id(state), None)
if char_list:
ranges = self.chars_to_ranges(char_list)
ranges_to_state[ranges] = state
ranges_list = ranges_to_state.keys()
ranges_list.sort()
for ranges in ranges_list:
key = self.ranges_to_string(ranges)
state = ranges_to_state[ranges]
file.write(" %s --> State %d\n" % (key, state['number']))
for key in ('bol', 'eol', 'eof', 'else'):
state = special_to_state.get(key, None)
if state:
file.write(" %s --> State %d\n" % (key, state['number']))
def chars_to_ranges(self, char_list):
char_list.sort()
i = 0
n = len(char_list)
result = []
while i < n:
c1 = ord(char_list[i])
c2 = c1
i = i + 1
while i < n and ord(char_list[i]) == c2 + 1:
i = i + 1
c2 = c2 + 1
result.append((chr(c1), chr(c2)))
return tuple(result)
def ranges_to_string(self, range_list):
return ','.join(map(self.range_to_string, range_list))
def range_to_string(self, range_tuple):
(c1, c2) = range_tuple
if c1 == c2:
return repr(c1)
else:
return "%s..%s" % (repr(c1), repr(c2))
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Plex/Regexps.py 0000664 0000000 0000000 00000037621 11446142532 0024120 0 ustar 00root root 0000000 0000000 #=======================================================================
#
# Python Lexical Analyser
#
# Regular Expressions
#
#=======================================================================
import array
import types
from sys import maxint as maxint
import Errors
#
# Constants
#
BOL = 'bol'
EOL = 'eol'
EOF = 'eof'
nl_code = ord('\n')
#
# Helper functions
#
def chars_to_ranges(s):
"""
Return a list of character codes consisting of pairs
[code1a, code1b, code2a, code2b,...] which cover all
the characters in |s|.
"""
char_list = list(s)
char_list.sort()
i = 0
n = len(char_list)
result = []
while i < n:
code1 = ord(char_list[i])
code2 = code1 + 1
i = i + 1
while i < n and code2 >= ord(char_list[i]):
code2 = code2 + 1
i = i + 1
result.append(code1)
result.append(code2)
return result
def uppercase_range(code1, code2):
"""
If the range of characters from code1 to code2-1 includes any
lower case letters, return the corresponding upper case range.
"""
code3 = max(code1, ord('a'))
code4 = min(code2, ord('z') + 1)
if code3 < code4:
d = ord('A') - ord('a')
return (code3 + d, code4 + d)
else:
return None
def lowercase_range(code1, code2):
"""
If the range of characters from code1 to code2-1 includes any
upper case letters, return the corresponding lower case range.
"""
code3 = max(code1, ord('A'))
code4 = min(code2, ord('Z') + 1)
if code3 < code4:
d = ord('a') - ord('A')
return (code3 + d, code4 + d)
else:
return None
def CodeRanges(code_list):
"""
Given a list of codes as returned by chars_to_ranges, return
an RE which will match a character in any of the ranges.
"""
re_list = []
for i in xrange(0, len(code_list), 2):
re_list.append(CodeRange(code_list[i], code_list[i + 1]))
return Alt(*re_list)
def CodeRange(code1, code2):
"""
CodeRange(code1, code2) is an RE which matches any character
with a code |c| in the range |code1| <= |c| < |code2|.
"""
if code1 <= nl_code < code2:
return Alt(RawCodeRange(code1, nl_code),
RawNewline,
RawCodeRange(nl_code + 1, code2))
else:
return RawCodeRange(code1, code2)
#
# Abstract classes
#
class RE(object):
"""RE is the base class for regular expression constructors.
The following operators are defined on REs:
re1 + re2 is an RE which matches |re1| followed by |re2|
re1 | re2 is an RE which matches either |re1| or |re2|
"""
nullable = 1 # True if this RE can match 0 input symbols
match_nl = 1 # True if this RE can match a string ending with '\n'
str = None # Set to a string to override the class's __str__ result
def build_machine(self, machine, initial_state, final_state,
match_bol, nocase):
"""
This method should add states to |machine| to implement this
RE, starting at |initial_state| and ending at |final_state|.
If |match_bol| is true, the RE must be able to match at the
beginning of a line. If nocase is true, upper and lower case
letters should be treated as equivalent.
"""
raise NotImplementedError("%s.build_machine not implemented" %
self.__class__.__name__)
def build_opt(self, m, initial_state, c):
"""
Given a state |s| of machine |m|, return a new state
reachable from |s| on character |c| or epsilon.
"""
s = m.new_state()
initial_state.link_to(s)
initial_state.add_transition(c, s)
return s
def __add__(self, other):
return Seq(self, other)
def __or__(self, other):
return Alt(self, other)
def __str__(self):
if self.str:
return self.str
else:
return self.calc_str()
def check_re(self, num, value):
if not isinstance(value, RE):
self.wrong_type(num, value, "Plex.RE instance")
def check_string(self, num, value):
if type(value) != type(''):
self.wrong_type(num, value, "string")
def check_char(self, num, value):
self.check_string(num, value)
if len(value) != 1:
raise Errors.PlexValueError("Invalid value for argument %d of Plex.%s."
"Expected a string of length 1, got: %s" % (
num, self.__class__.__name__, repr(value)))
def wrong_type(self, num, value, expected):
if type(value) == types.InstanceType:
got = "%s.%s instance" % (
value.__class__.__module__, value.__class__.__name__)
else:
got = type(value).__name__
raise Errors.PlexTypeError("Invalid type for argument %d of Plex.%s "
"(expected %s, got %s" % (
num, self.__class__.__name__, expected, got))
#
# Primitive RE constructors
# -------------------------
#
# These are the basic REs from which all others are built.
#
## class Char(RE):
## """
## Char(c) is an RE which matches the character |c|.
## """
## nullable = 0
## def __init__(self, char):
## self.char = char
## self.match_nl = char == '\n'
## def build_machine(self, m, initial_state, final_state, match_bol, nocase):
## c = self.char
## if match_bol and c != BOL:
## s1 = self.build_opt(m, initial_state, BOL)
## else:
## s1 = initial_state
## if c == '\n' or c == EOF:
## s1 = self.build_opt(m, s1, EOL)
## if len(c) == 1:
## code = ord(self.char)
## s1.add_transition((code, code+1), final_state)
## if nocase and is_letter_code(code):
## code2 = other_case_code(code)
## s1.add_transition((code2, code2+1), final_state)
## else:
## s1.add_transition(c, final_state)
## def calc_str(self):
## return "Char(%s)" % repr(self.char)
def Char(c):
"""
Char(c) is an RE which matches the character |c|.
"""
if len(c) == 1:
result = CodeRange(ord(c), ord(c) + 1)
else:
result = SpecialSymbol(c)
result.str = "Char(%s)" % repr(c)
return result
class RawCodeRange(RE):
"""
RawCodeRange(code1, code2) is a low-level RE which matches any character
with a code |c| in the range |code1| <= |c| < |code2|, where the range
does not include newline. For internal use only.
"""
nullable = 0
match_nl = 0
range = None # (code, code)
uppercase_range = None # (code, code) or None
lowercase_range = None # (code, code) or None
def __init__(self, code1, code2):
self.range = (code1, code2)
self.uppercase_range = uppercase_range(code1, code2)
self.lowercase_range = lowercase_range(code1, code2)
def build_machine(self, m, initial_state, final_state, match_bol, nocase):
if match_bol:
initial_state = self.build_opt(m, initial_state, BOL)
initial_state.add_transition(self.range, final_state)
if nocase:
if self.uppercase_range:
initial_state.add_transition(self.uppercase_range, final_state)
if self.lowercase_range:
initial_state.add_transition(self.lowercase_range, final_state)
def calc_str(self):
return "CodeRange(%d,%d)" % (self.code1, self.code2)
class _RawNewline(RE):
"""
RawNewline is a low-level RE which matches a newline character.
For internal use only.
"""
nullable = 0
match_nl = 1
def build_machine(self, m, initial_state, final_state, match_bol, nocase):
if match_bol:
initial_state = self.build_opt(m, initial_state, BOL)
s = self.build_opt(m, initial_state, EOL)
s.add_transition((nl_code, nl_code + 1), final_state)
RawNewline = _RawNewline()
class SpecialSymbol(RE):
"""
SpecialSymbol(sym) is an RE which matches the special input
symbol |sym|, which is one of BOL, EOL or EOF.
"""
nullable = 0
match_nl = 0
sym = None
def __init__(self, sym):
self.sym = sym
def build_machine(self, m, initial_state, final_state, match_bol, nocase):
# Sequences 'bol bol' and 'bol eof' are impossible, so only need
# to allow for bol if sym is eol
if match_bol and self.sym == EOL:
initial_state = self.build_opt(m, initial_state, BOL)
initial_state.add_transition(self.sym, final_state)
class Seq(RE):
"""Seq(re1, re2, re3...) is an RE which matches |re1| followed by
|re2| followed by |re3|..."""
def __init__(self, *re_list):
nullable = 1
for i in xrange(len(re_list)):
re = re_list[i]
self.check_re(i, re)
nullable = nullable and re.nullable
self.re_list = re_list
self.nullable = nullable
i = len(re_list)
match_nl = 0
while i:
i = i - 1
re = re_list[i]
if re.match_nl:
match_nl = 1
break
if not re.nullable:
break
self.match_nl = match_nl
def build_machine(self, m, initial_state, final_state, match_bol, nocase):
re_list = self.re_list
if len(re_list) == 0:
initial_state.link_to(final_state)
else:
s1 = initial_state
n = len(re_list)
for i in xrange(n):
if i < n - 1:
s2 = m.new_state()
else:
s2 = final_state
re = re_list[i]
re.build_machine(m, s1, s2, match_bol, nocase)
s1 = s2
match_bol = re.match_nl or (match_bol and re.nullable)
def calc_str(self):
return "Seq(%s)" % ','.join(map(str, self.re_list))
class Alt(RE):
"""Alt(re1, re2, re3...) is an RE which matches either |re1| or
|re2| or |re3|..."""
def __init__(self, *re_list):
self.re_list = re_list
nullable = 0
match_nl = 0
nullable_res = []
non_nullable_res = []
i = 1
for re in re_list:
self.check_re(i, re)
if re.nullable:
nullable_res.append(re)
nullable = 1
else:
non_nullable_res.append(re)
if re.match_nl:
match_nl = 1
i = i + 1
self.nullable_res = nullable_res
self.non_nullable_res = non_nullable_res
self.nullable = nullable
self.match_nl = match_nl
def build_machine(self, m, initial_state, final_state, match_bol, nocase):
for re in self.nullable_res:
re.build_machine(m, initial_state, final_state, match_bol, nocase)
if self.non_nullable_res:
if match_bol:
initial_state = self.build_opt(m, initial_state, BOL)
for re in self.non_nullable_res:
re.build_machine(m, initial_state, final_state, 0, nocase)
def calc_str(self):
return "Alt(%s)" % ','.join(map(str, self.re_list))
class Rep1(RE):
"""Rep1(re) is an RE which matches one or more repetitions of |re|."""
def __init__(self, re):
self.check_re(1, re)
self.re = re
self.nullable = re.nullable
self.match_nl = re.match_nl
def build_machine(self, m, initial_state, final_state, match_bol, nocase):
s1 = m.new_state()
s2 = m.new_state()
initial_state.link_to(s1)
self.re.build_machine(m, s1, s2, match_bol or self.re.match_nl, nocase)
s2.link_to(s1)
s2.link_to(final_state)
def calc_str(self):
return "Rep1(%s)" % self.re
class SwitchCase(RE):
"""
SwitchCase(re, nocase) is an RE which matches the same strings as RE,
but treating upper and lower case letters according to |nocase|. If
|nocase| is true, case is ignored, otherwise it is not.
"""
re = None
nocase = None
def __init__(self, re, nocase):
self.re = re
self.nocase = nocase
self.nullable = re.nullable
self.match_nl = re.match_nl
def build_machine(self, m, initial_state, final_state, match_bol, nocase):
self.re.build_machine(m, initial_state, final_state, match_bol,
self.nocase)
def calc_str(self):
if self.nocase:
name = "NoCase"
else:
name = "Case"
return "%s(%s)" % (name, self.re)
#
# Composite RE constructors
# -------------------------
#
# These REs are defined in terms of the primitive REs.
#
Empty = Seq()
Empty.__doc__ = \
"""
Empty is an RE which matches the empty string.
"""
Empty.str = "Empty"
def Str1(s):
"""
Str1(s) is an RE which matches the literal string |s|.
"""
result = Seq(*tuple(map(Char, s)))
result.str = "Str(%s)" % repr(s)
return result
def Str(*strs):
"""
Str(s) is an RE which matches the literal string |s|.
Str(s1, s2, s3, ...) is an RE which matches any of |s1| or |s2| or |s3|...
"""
if len(strs) == 1:
return Str1(strs[0])
else:
result = Alt(*tuple(map(Str1, strs)))
result.str = "Str(%s)" % ','.join(map(repr, strs))
return result
def Any(s):
"""
Any(s) is an RE which matches any character in the string |s|.
"""
#result = apply(Alt, tuple(map(Char, s)))
result = CodeRanges(chars_to_ranges(s))
result.str = "Any(%s)" % repr(s)
return result
def AnyBut(s):
"""
AnyBut(s) is an RE which matches any character (including
newline) which is not in the string |s|.
"""
ranges = chars_to_ranges(s)
ranges.insert(0, -maxint)
ranges.append(maxint)
result = CodeRanges(ranges)
result.str = "AnyBut(%s)" % repr(s)
return result
AnyChar = AnyBut("")
AnyChar.__doc__ = \
"""
AnyChar is an RE which matches any single character (including a newline).
"""
AnyChar.str = "AnyChar"
def Range(s1, s2 = None):
"""
Range(c1, c2) is an RE which matches any single character in the range
|c1| to |c2| inclusive.
Range(s) where |s| is a string of even length is an RE which matches
any single character in the ranges |s[0]| to |s[1]|, |s[2]| to |s[3]|,...
"""
if s2:
result = CodeRange(ord(s1), ord(s2) + 1)
result.str = "Range(%s,%s)" % (s1, s2)
else:
ranges = []
for i in range(0, len(s1), 2):
ranges.append(CodeRange(ord(s1[i]), ord(s1[i+1]) + 1))
result = Alt(*ranges)
result.str = "Range(%s)" % repr(s1)
return result
def Opt(re):
"""
Opt(re) is an RE which matches either |re| or the empty string.
"""
result = Alt(re, Empty)
result.str = "Opt(%s)" % re
return result
def Rep(re):
"""
Rep(re) is an RE which matches zero or more repetitions of |re|.
"""
result = Opt(Rep1(re))
result.str = "Rep(%s)" % re
return result
def NoCase(re):
"""
NoCase(re) is an RE which matches the same strings as RE, but treating
upper and lower case letters as equivalent.
"""
return SwitchCase(re, nocase = 1)
def Case(re):
"""
Case(re) is an RE which matches the same strings as RE, but treating
upper and lower case letters as distinct, i.e. it cancels the effect
of any enclosing NoCase().
"""
return SwitchCase(re, nocase = 0)
#
# RE Constants
#
Bol = Char(BOL)
Bol.__doc__ = \
"""
Bol is an RE which matches the beginning of a line.
"""
Bol.str = "Bol"
Eol = Char(EOL)
Eol.__doc__ = \
"""
Eol is an RE which matches the end of a line.
"""
Eol.str = "Eol"
Eof = Char(EOF)
Eof.__doc__ = \
"""
Eof is an RE which matches the end of the file.
"""
Eof.str = "Eof"
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Plex/Scanners.pxd 0000664 0000000 0000000 00000002237 11446142532 0024415 0 ustar 00root root 0000000 0000000 import cython
cdef class Scanner:
cdef public lexicon
cdef public stream
cdef public name
cdef public buffer
cdef public Py_ssize_t buf_start_pos
cdef public Py_ssize_t next_pos
cdef public Py_ssize_t cur_pos
cdef public Py_ssize_t cur_line
cdef public Py_ssize_t cur_line_start
cdef public Py_ssize_t start_pos
cdef public Py_ssize_t start_line
cdef public Py_ssize_t start_col
cdef public text
cdef public initial_state # int?
cdef public state_name
cdef public list queue
cdef public bint trace
cdef public cur_char
cdef public int input_state
cdef public level
@cython.locals(input_state=long)
cpdef next_char(self)
@cython.locals(queue=list)
cpdef tuple read(self)
cpdef tuple scan_a_token(self)
cpdef tuple position(self)
@cython.locals(cur_pos=long, cur_line=long, cur_line_start=long,
input_state=long, next_pos=long,
buf_start_pos=long, buf_len=long, buf_index=long,
trace=bint, discard=long)
cpdef run_machine_inlined(self)
cpdef begin(self, state)
cpdef produce(self, value, text = *)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Plex/Scanners.py 0000664 0000000 0000000 00000023632 11446142532 0024254 0 ustar 00root root 0000000 0000000 #=======================================================================
#
# Python Lexical Analyser
#
#
# Scanning an input stream
#
#=======================================================================
import cython
cython.declare(BOL=object, EOL=object, EOF=object)
import Errors
from Regexps import BOL, EOL, EOF
class Scanner(object):
"""
A Scanner is used to read tokens from a stream of characters
using the token set specified by a Plex.Lexicon.
Constructor:
Scanner(lexicon, stream, name = '')
See the docstring of the __init__ method for details.
Methods:
See the docstrings of the individual methods for more
information.
read() --> (value, text)
Reads the next lexical token from the stream.
position() --> (name, line, col)
Returns the position of the last token read using the
read() method.
begin(state_name)
Causes scanner to change state.
produce(value [, text])
Causes return of a token value to the caller of the
Scanner.
"""
# lexicon = None # Lexicon
# stream = None # file-like object
# name = ''
# buffer = ''
# buf_start_pos = 0 # position in input of start of buffer
# next_pos = 0 # position in input of next char to read
# cur_pos = 0 # position in input of current char
# cur_line = 1 # line number of current char
# cur_line_start = 0 # position in input of start of current line
# start_pos = 0 # position in input of start of token
# start_line = 0 # line number of start of token
# start_col = 0 # position in line of start of token
# text = None # text of last token read
# initial_state = None # Node
# state_name = '' # Name of initial state
# queue = None # list of tokens to be returned
# trace = 0
def __init__(self, lexicon, stream, name = '', initial_pos = None):
"""
Scanner(lexicon, stream, name = '')
|lexicon| is a Plex.Lexicon instance specifying the lexical tokens
to be recognised.
|stream| can be a file object or anything which implements a
compatible read() method.
|name| is optional, and may be the name of the file being
scanned or any other identifying string.
"""
self.trace = 0
self.buffer = u''
self.buf_start_pos = 0
self.next_pos = 0
self.cur_pos = 0
self.cur_line = 1
self.start_pos = 0
self.start_line = 0
self.start_col = 0
self.text = None
self.state_name = None
self.lexicon = lexicon
self.stream = stream
self.name = name
self.queue = []
self.initial_state = None
self.begin('')
self.next_pos = 0
self.cur_pos = 0
self.cur_line_start = 0
self.cur_char = BOL
self.input_state = 1
if initial_pos is not None:
self.cur_line, self.cur_line_start = initial_pos[1], -initial_pos[2]
def read(self):
"""
Read the next lexical token from the stream and return a
tuple (value, text), where |value| is the value associated with
the token as specified by the Lexicon, and |text| is the actual
string read from the stream. Returns (None, '') on end of file.
"""
queue = self.queue
while not queue:
self.text, action = self.scan_a_token()
if action is None:
self.produce(None)
self.eof()
else:
value = action.perform(self, self.text)
if value is not None:
self.produce(value)
result = queue[0]
del queue[0]
return result
def scan_a_token(self):
"""
Read the next input sequence recognised by the machine
and return (text, action). Returns ('', None) on end of
file.
"""
self.start_pos = self.cur_pos
self.start_line = self.cur_line
self.start_col = self.cur_pos - self.cur_line_start
action = self.run_machine_inlined()
if action is not None:
if self.trace:
print("Scanner: read: Performing %s %d:%d" % (
action, self.start_pos, self.cur_pos))
text = self.buffer[self.start_pos - self.buf_start_pos :
self.cur_pos - self.buf_start_pos]
return (text, action)
else:
if self.cur_pos == self.start_pos:
if self.cur_char is EOL:
self.next_char()
if self.cur_char is None or self.cur_char is EOF:
return (u'', None)
raise Errors.UnrecognizedInput(self, self.state_name)
def run_machine_inlined(self):
"""
Inlined version of run_machine for speed.
"""
state = self.initial_state
cur_pos = self.cur_pos
cur_line = self.cur_line
cur_line_start = self.cur_line_start
cur_char = self.cur_char
input_state = self.input_state
next_pos = self.next_pos
buffer = self.buffer
buf_start_pos = self.buf_start_pos
buf_len = len(buffer)
backup_state = None
trace = self.trace
while 1:
if trace: #TRACE#
print("State %d, %d/%d:%s -->" % ( #TRACE#
state['number'], input_state, cur_pos, repr(cur_char))) #TRACE#
# Begin inlined self.save_for_backup()
#action = state.action #@slow
action = state['action'] #@fast
if action is not None:
backup_state = (
action, cur_pos, cur_line, cur_line_start, cur_char, input_state, next_pos)
# End inlined self.save_for_backup()
c = cur_char
#new_state = state.new_state(c) #@slow
new_state = state.get(c, -1) #@fast
if new_state == -1: #@fast
new_state = c and state.get('else') #@fast
if new_state:
if trace: #TRACE#
print("State %d" % new_state['number']) #TRACE#
state = new_state
# Begin inlined: self.next_char()
if input_state == 1:
cur_pos = next_pos
# Begin inlined: c = self.read_char()
buf_index = next_pos - buf_start_pos
if buf_index < buf_len:
c = buffer[buf_index]
next_pos = next_pos + 1
else:
discard = self.start_pos - buf_start_pos
data = self.stream.read(0x1000)
buffer = self.buffer[discard:] + data
self.buffer = buffer
buf_start_pos = buf_start_pos + discard
self.buf_start_pos = buf_start_pos
buf_len = len(buffer)
buf_index = buf_index - discard
if data:
c = buffer[buf_index]
next_pos = next_pos + 1
else:
c = u''
# End inlined: c = self.read_char()
if c == u'\n':
cur_char = EOL
input_state = 2
elif not c:
cur_char = EOL
input_state = 4
else:
cur_char = c
elif input_state == 2:
cur_char = u'\n'
input_state = 3
elif input_state == 3:
cur_line = cur_line + 1
cur_line_start = cur_pos = next_pos
cur_char = BOL
input_state = 1
elif input_state == 4:
cur_char = EOF
input_state = 5
else: # input_state = 5
cur_char = u''
# End inlined self.next_char()
else: # not new_state
if trace: #TRACE#
print("blocked") #TRACE#
# Begin inlined: action = self.back_up()
if backup_state is not None:
(action, cur_pos, cur_line, cur_line_start,
cur_char, input_state, next_pos) = backup_state
else:
action = None
break # while 1
# End inlined: action = self.back_up()
self.cur_pos = cur_pos
self.cur_line = cur_line
self.cur_line_start = cur_line_start
self.cur_char = cur_char
self.input_state = input_state
self.next_pos = next_pos
if trace: #TRACE#
if action is not None: #TRACE#
print("Doing %s" % action) #TRACE#
return action
def next_char(self):
input_state = self.input_state
if self.trace:
print("Scanner: next: %s [%d] %d" % (" "*20, input_state, self.cur_pos))
if input_state == 1:
self.cur_pos = self.next_pos
c = self.read_char()
if c == u'\n':
self.cur_char = EOL
self.input_state = 2
elif not c:
self.cur_char = EOL
self.input_state = 4
else:
self.cur_char = c
elif input_state == 2:
self.cur_char = u'\n'
self.input_state = 3
elif input_state == 3:
self.cur_line = self.cur_line + 1
self.cur_line_start = self.cur_pos = self.next_pos
self.cur_char = BOL
self.input_state = 1
elif input_state == 4:
self.cur_char = EOF
self.input_state = 5
else: # input_state = 5
self.cur_char = u''
if self.trace:
print("--> [%d] %d %s" % (input_state, self.cur_pos, repr(self.cur_char)))
def position(self):
"""
Return a tuple (name, line, col) representing the location of
the last token read using the read() method. |name| is the
name that was provided to the Scanner constructor; |line|
is the line number in the stream (1-based); |col| is the
position within the line of the first character of the token
(0-based).
"""
return (self.name, self.start_line, self.start_col)
def begin(self, state_name):
"""Set the current state of the scanner to the named state."""
self.initial_state = (
self.lexicon.get_initial_state(state_name))
self.state_name = state_name
def produce(self, value, text = None):
"""
Called from an action procedure, causes |value| to be returned
as the token value from read(). If |text| is supplied, it is
returned in place of the scanned text.
produce() can be called more than once during a single call to an action
procedure, in which case the tokens are queued up and returned one
at a time by subsequent calls to read(), until the queue is empty,
whereupon scanning resumes.
"""
if text is None:
text = self.text
self.queue.append((value, text))
def eof(self):
"""
Override this method if you want something to be done at
end of file.
"""
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Plex/Timing.py 0000664 0000000 0000000 00000000623 11446142532 0023722 0 ustar 00root root 0000000 0000000 #
# Get time in platform-dependent way
#
import os
from sys import platform, exit, stderr
if platform == 'mac':
import MacOS
def time():
return MacOS.GetTicks() / 60.0
timekind = "real"
elif hasattr(os, 'times'):
def time():
t = os.times()
return t[0] + t[1]
timekind = "cpu"
else:
stderr.write(
"Don't know how to get time on platform %s\n" % repr(platform))
exit(1)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Plex/Traditional.py 0000664 0000000 0000000 00000006716 11446142532 0024756 0 ustar 00root root 0000000 0000000 #=======================================================================
#
# Python Lexical Analyser
#
# Traditional Regular Expression Syntax
#
#=======================================================================
from Regexps import Alt, Seq, Rep, Rep1, Opt, Any, AnyBut, Bol, Eol, Char
from Errors import PlexError
class RegexpSyntaxError(PlexError):
pass
def re(s):
"""
Convert traditional string representation of regular expression |s|
into Plex representation.
"""
return REParser(s).parse_re()
class REParser(object):
def __init__(self, s):
self.s = s
self.i = -1
self.end = 0
self.next()
def parse_re(self):
re = self.parse_alt()
if not self.end:
self.error("Unexpected %s" % repr(self.c))
return re
def parse_alt(self):
"""Parse a set of alternative regexps."""
re = self.parse_seq()
if self.c == '|':
re_list = [re]
while self.c == '|':
self.next()
re_list.append(self.parse_seq())
re = Alt(*re_list)
return re
def parse_seq(self):
"""Parse a sequence of regexps."""
re_list = []
while not self.end and not self.c in "|)":
re_list.append(self.parse_mod())
return Seq(*re_list)
def parse_mod(self):
"""Parse a primitive regexp followed by *, +, ? modifiers."""
re = self.parse_prim()
while not self.end and self.c in "*+?":
if self.c == '*':
re = Rep(re)
elif self.c == '+':
re = Rep1(re)
else: # self.c == '?'
re = Opt(re)
self.next()
return re
def parse_prim(self):
"""Parse a primitive regexp."""
c = self.get()
if c == '.':
re = AnyBut("\n")
elif c == '^':
re = Bol
elif c == '$':
re = Eol
elif c == '(':
re = self.parse_alt()
self.expect(')')
elif c == '[':
re = self.parse_charset()
self.expect(']')
else:
if c == '\\':
c = self.get()
re = Char(c)
return re
def parse_charset(self):
"""Parse a charset. Does not include the surrounding []."""
char_list = []
invert = 0
if self.c == '^':
invert = 1
self.next()
if self.c == ']':
char_list.append(']')
self.next()
while not self.end and self.c != ']':
c1 = self.get()
if self.c == '-' and self.lookahead(1) != ']':
self.next()
c2 = self.get()
for a in xrange(ord(c1), ord(c2) + 1):
char_list.append(chr(a))
else:
char_list.append(c1)
chars = ''.join(char_list)
if invert:
return AnyBut(chars)
else:
return Any(chars)
def next(self):
"""Advance to the next char."""
s = self.s
i = self.i = self.i + 1
if i < len(s):
self.c = s[i]
else:
self.c = ''
self.end = 1
def get(self):
if self.end:
self.error("Premature end of string")
c = self.c
self.next()
return c
def lookahead(self, n):
"""Look ahead n chars."""
j = self.i + n
if j < len(self.s):
return self.s[j]
else:
return ''
def expect(self, c):
"""
Expect to find character |c| at current position.
Raises an exception otherwise.
"""
if self.c == c:
self.next()
else:
self.error("Missing %s" % repr(c))
def error(self, mess):
"""Raise exception to signal syntax error in regexp."""
raise RegexpSyntaxError("Syntax error in regexp %s at position %d: %s" % (
repr(self.s), self.i, mess))
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Plex/Transitions.py 0000664 0000000 0000000 00000014136 11446142532 0025014 0 ustar 00root root 0000000 0000000 #
# Plex - Transition Maps
#
# This version represents state sets direcly as dicts
# for speed.
#
from copy import copy
from sys import maxint as maxint
class TransitionMap(object):
"""
A TransitionMap maps an input event to a set of states.
An input event is one of: a range of character codes,
the empty string (representing an epsilon move), or one
of the special symbols BOL, EOL, EOF.
For characters, this implementation compactly represents
the map by means of a list:
[code_0, states_0, code_1, states_1, code_2, states_2,
..., code_n-1, states_n-1, code_n]
where |code_i| is a character code, and |states_i| is a
set of states corresponding to characters with codes |c|
in the range |code_i| <= |c| <= |code_i+1|.
The following invariants hold:
n >= 1
code_0 == -maxint
code_n == maxint
code_i < code_i+1 for i in 0..n-1
states_0 == states_n-1
Mappings for the special events '', BOL, EOL, EOF are
kept separately in a dictionary.
"""
map = None # The list of codes and states
special = None # Mapping for special events
def __init__(self, map = None, special = None):
if not map:
map = [-maxint, {}, maxint]
if not special:
special = {}
self.map = map
self.special = special
#self.check() ###
def add(self, event, new_state,
TupleType = tuple):
"""
Add transition to |new_state| on |event|.
"""
if type(event) is TupleType:
code0, code1 = event
i = self.split(code0)
j = self.split(code1)
map = self.map
while i < j:
map[i + 1][new_state] = 1
i = i + 2
else:
self.get_special(event)[new_state] = 1
def add_set(self, event, new_set,
TupleType = tuple):
"""
Add transitions to the states in |new_set| on |event|.
"""
if type(event) is TupleType:
code0, code1 = event
i = self.split(code0)
j = self.split(code1)
map = self.map
while i < j:
map[i + 1].update(new_set)
i = i + 2
else:
self.get_special(event).update(new_set)
def get_epsilon(self,
none = None):
"""
Return the mapping for epsilon, or None.
"""
return self.special.get('', none)
def iteritems(self,
len = len):
"""
Return the mapping as an iterable of ((code1, code2), state_set) and
(special_event, state_set) pairs.
"""
result = []
map = self.map
else_set = map[1]
i = 0
n = len(map) - 1
code0 = map[0]
while i < n:
set = map[i + 1]
code1 = map[i + 2]
if set or else_set:
result.append(((code0, code1), set))
code0 = code1
i = i + 2
for event, set in self.special.iteritems():
if set:
result.append((event, set))
return iter(result)
items = iteritems
# ------------------- Private methods --------------------
def split(self, code,
len = len, maxint = maxint):
"""
Search the list for the position of the split point for |code|,
inserting a new split point if necessary. Returns index |i| such
that |code| == |map[i]|.
"""
# We use a funky variation on binary search.
map = self.map
hi = len(map) - 1
# Special case: code == map[-1]
if code == maxint:
return hi
# General case
lo = 0
# loop invariant: map[lo] <= code < map[hi] and hi - lo >= 2
while hi - lo >= 4:
# Find midpoint truncated to even index
mid = ((lo + hi) // 2) & ~1
if code < map[mid]:
hi = mid
else:
lo = mid
# map[lo] <= code < map[hi] and hi - lo == 2
if map[lo] == code:
return lo
else:
map[hi:hi] = [code, map[hi - 1].copy()]
#self.check() ###
return hi
def get_special(self, event):
"""
Get state set for special event, adding a new entry if necessary.
"""
special = self.special
set = special.get(event, None)
if not set:
set = {}
special[event] = set
return set
# --------------------- Conversion methods -----------------------
def __str__(self):
map_strs = []
map = self.map
n = len(map)
i = 0
while i < n:
code = map[i]
if code == -maxint:
code_str = "-inf"
elif code == maxint:
code_str = "inf"
else:
code_str = str(code)
map_strs.append(code_str)
i = i + 1
if i < n:
map_strs.append(state_set_str(map[i]))
i = i + 1
special_strs = {}
for event, set in self.special.iteritems():
special_strs[event] = state_set_str(set)
return "[%s]+%s" % (
','.join(map_strs),
special_strs
)
# --------------------- Debugging methods -----------------------
def check(self):
"""Check data structure integrity."""
if not self.map[-3] < self.map[-1]:
print(self)
assert 0
def dump(self, file):
map = self.map
i = 0
n = len(map) - 1
while i < n:
self.dump_range(map[i], map[i + 2], map[i + 1], file)
i = i + 2
for event, set in self.special.iteritems():
if set:
if not event:
event = 'empty'
self.dump_trans(event, set, file)
def dump_range(self, code0, code1, set, file):
if set:
if code0 == -maxint:
if code1 == maxint:
k = "any"
else:
k = "< %s" % self.dump_char(code1)
elif code1 == maxint:
k = "> %s" % self.dump_char(code0 - 1)
elif code0 == code1 - 1:
k = self.dump_char(code0)
else:
k = "%s..%s" % (self.dump_char(code0),
self.dump_char(code1 - 1))
self.dump_trans(k, set, file)
def dump_char(self, code):
if 0 <= code <= 255:
return repr(chr(code))
else:
return "chr(%d)" % code
def dump_trans(self, key, set, file):
file.write(" %s --> %s\n" % (key, self.dump_set(set)))
def dump_set(self, set):
return state_set_str(set)
#
# State set manipulation functions
#
#def merge_state_sets(set1, set2):
# for state in set2.keys():
# set1[state] = 1
def state_set_str(set):
return "[%s]" % ','.join(["S%d" % state.number for state in set])
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Plex/__init__.py 0000664 0000000 0000000 00000002330 11446142532 0024227 0 ustar 00root root 0000000 0000000 #=======================================================================
#
# Python Lexical Analyser
#
#=======================================================================
"""
The Plex module provides lexical analysers with similar capabilities
to GNU Flex. The following classes and functions are exported;
see the attached docstrings for more information.
Scanner For scanning a character stream under the
direction of a Lexicon.
Lexicon For constructing a lexical definition
to be used by a Scanner.
Str, Any, AnyBut, AnyChar, Seq, Alt, Opt, Rep, Rep1,
Bol, Eol, Eof, Empty
Regular expression constructors, for building pattern
definitions for a Lexicon.
State For defining scanner states when creating a
Lexicon.
TEXT, IGNORE, Begin
Actions for associating with patterns when
creating a Lexicon.
"""
from Actions import TEXT, IGNORE, Begin
from Lexicons import Lexicon, State
from Regexps import RE, Seq, Alt, Rep1, Empty, Str, Any, AnyBut, AnyChar, Range
from Regexps import Opt, Rep, Bol, Eol, Eof, Case, NoCase
from Scanners import Scanner
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Runtime/ 0000775 0000000 0000000 00000000000 11446142532 0022633 5 ustar 00root root 0000000 0000000 cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Runtime/__init__.py 0000664 0000000 0000000 00000000000 11446142532 0024732 0 ustar 00root root 0000000 0000000 cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Runtime/refnanny.pyx 0000664 0000000 0000000 00000013401 11446142532 0025214 0 ustar 00root root 0000000 0000000 from cpython.ref cimport PyObject, Py_INCREF, Py_DECREF, Py_XDECREF
from cpython.exc cimport PyErr_Fetch, PyErr_Restore
loglevel = 0
reflog = []
cdef log(level, action, obj, lineno):
if loglevel >= level:
reflog.append((lineno, action, id(obj)))
LOG_NONE, LOG_ALL = range(2)
class Context(object):
def __init__(self, name, line=0, filename=None):
self.name = name
self.start = line
self.filename = filename
self.refs = {} # id -> (count, [lineno])
self.errors = []
def regref(self, obj, lineno, is_null):
log(LOG_ALL, u'regref', u"" if is_null else obj, lineno)
if is_null:
self.errors.append(u"NULL argument on line %d" % lineno)
return
id_ = id(obj)
count, linenumbers = self.refs.get(id_, (0, []))
self.refs[id_] = (count + 1, linenumbers)
linenumbers.append(lineno)
def delref(self, obj, lineno, is_null):
# returns whether it is ok to do the decref operation
log(LOG_ALL, u'delref', u"" if is_null else obj, lineno)
if is_null:
self.errors.append(u"NULL argument on line %d" % lineno)
return False
id_ = id(obj)
count, linenumbers = self.refs.get(id_, (0, []))
if count == 0:
self.errors.append(u"Too many decrefs on line %d, reference acquired on lines %r" %
(lineno, linenumbers))
return False
elif count == 1:
del self.refs[id_]
return True
else:
self.refs[id_] = (count - 1, linenumbers)
return True
def end(self):
if len(self.refs) > 0:
msg = u""
for count, linenos in self.refs.itervalues():
msg += u"\n Acquired on lines: " + u", ".join([u"%d" % x for x in linenos])
self.errors.append(u"References leaked: %s" % msg)
if self.errors:
return u"\n".join(self.errors)
else:
return None
cdef void report_unraisable(object e=None):
try:
if e is None:
import sys
e = sys.exc_info()[1]
print u"refnanny raised an exception: %s" % e
except:
pass # We absolutely cannot exit with an exception
# All Python operations must happen after any existing
# exception has been fetched, in case we are called from
# exception-handling code.
cdef PyObject* SetupContext(char* funcname, int lineno, char* filename) except NULL:
if Context is None:
# Context may be None during finalize phase.
# In that case, we don't want to be doing anything fancy
# like caching and resetting exceptions.
return NULL
cdef PyObject* type = NULL, *value = NULL, *tb = NULL
cdef PyObject* result = NULL
PyErr_Fetch(&type, &value, &tb)
try:
ctx = Context(funcname, lineno, filename)
Py_INCREF(ctx)
result = ctx
except Exception, e:
report_unraisable(e)
PyErr_Restore(type, value, tb)
return result
cdef void GOTREF(PyObject* ctx, PyObject* p_obj, int lineno):
if ctx == NULL: return
cdef PyObject* type = NULL, *value = NULL, *tb = NULL
PyErr_Fetch(&type, &value, &tb)
try:
try:
if p_obj is NULL:
(ctx).regref(None, lineno, True)
else:
(ctx).regref(p_obj, lineno, False)
except:
report_unraisable()
except:
# __Pyx_GetException may itself raise errors
pass
PyErr_Restore(type, value, tb)
cdef int GIVEREF_and_report(PyObject* ctx, PyObject* p_obj, int lineno):
if ctx == NULL: return 1
cdef PyObject* type = NULL, *value = NULL, *tb = NULL
cdef bint decref_ok = False
PyErr_Fetch(&type, &value, &tb)
try:
try:
if p_obj is NULL:
decref_ok = (ctx).delref(None, lineno, True)
else:
decref_ok = (ctx).delref(p_obj, lineno, False)
except:
report_unraisable()
except:
# __Pyx_GetException may itself raise errors
pass
PyErr_Restore(type, value, tb)
return decref_ok
cdef void GIVEREF(PyObject* ctx, PyObject* p_obj, int lineno):
GIVEREF_and_report(ctx, p_obj, lineno)
cdef void INCREF(PyObject* ctx, PyObject* obj, int lineno):
if obj is not NULL: Py_INCREF(obj)
GOTREF(ctx, obj, lineno)
cdef void DECREF(PyObject* ctx, PyObject* obj, int lineno):
if GIVEREF_and_report(ctx, obj, lineno):
if obj is not NULL: Py_DECREF(obj)
cdef void FinishContext(PyObject** ctx):
if ctx == NULL or ctx[0] == NULL: return
cdef PyObject* type = NULL, *value = NULL, *tb = NULL
cdef object errors = None
PyErr_Fetch(&type, &value, &tb)
try:
try:
errors = (ctx[0]).end()
pos = (ctx[0]).filename, (ctx[0]).name
if errors:
print u"%s: %s()" % pos
print errors
except:
report_unraisable()
except:
# __Pyx_GetException may itself raise errors
pass
Py_DECREF(ctx[0])
ctx[0] = NULL
PyErr_Restore(type, value, tb)
ctypedef struct RefNannyAPIStruct:
void (*INCREF)(PyObject*, PyObject*, int)
void (*DECREF)(PyObject*, PyObject*, int)
void (*GOTREF)(PyObject*, PyObject*, int)
void (*GIVEREF)(PyObject*, PyObject*, int)
PyObject* (*SetupContext)(char*, int, char*) except NULL
void (*FinishContext)(PyObject**)
cdef RefNannyAPIStruct api
api.INCREF = INCREF
api.DECREF = DECREF
api.GOTREF = GOTREF
api.GIVEREF = GIVEREF
api.SetupContext = SetupContext
api.FinishContext = FinishContext
cdef extern from "Python.h":
object PyLong_FromVoidPtr(void*)
RefNannyAPI = PyLong_FromVoidPtr(&api)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Shadow.py 0000664 0000000 0000000 00000011362 11446142532 0023012 0 ustar 00root root 0000000 0000000 compiled = False
def empty_decorator(x):
return x
def locals(**arg_types):
return empty_decorator
# Special functions
def cdiv(a, b):
q = a / b
if q < 0:
q += 1
def cmod(a, b):
r = a % b
if (a*b) < 0:
r -= b
return r
# Emulated language constructs
def cast(type, arg):
if hasattr(type, '__call__'):
return type(arg)
else:
return arg
def sizeof(arg):
return 1
def typeof(arg):
return type(arg)
def address(arg):
return pointer(type(arg))([arg])
def declare(type=None, value=None, **kwds):
if type is not None and hasattr(type, '__call__'):
if value:
return type(value)
else:
return type()
else:
return value
# Emulated types
class CythonType(object):
def _pointer(self, n=1):
for i in range(n):
self = pointer(self)
return self
def __getitem__(self, ix):
return array(self, ix)
class PointerType(CythonType):
def __init__(self, value=None):
if isinstance(value, ArrayType):
self._items = [cast(self._basetype, a) for a in value._items]
elif isinstance(value, list):
self._items = [cast(self._basetype, a) for a in value]
elif value is None:
self._items = []
else:
raise ValueError
def __getitem__(self, ix):
if ix < 0:
raise IndexError("negative indexing not allowed in C")
return self._items[ix]
def __setitem__(self, ix, value):
if ix < 0:
raise IndexError("negative indexing not allowed in C")
self._items[ix] = cast(self._basetype, value)
class ArrayType(PointerType):
def __init__(self):
self._items = [None] * self._n
class StructType(CythonType):
def __init__(self, **data):
for key, value in data.iteritems():
setattr(self, key, value)
def __setattr__(self, key, value):
if key in self._members:
self.__dict__[key] = cast(self._members[key], value)
else:
raise AttributeError("Struct has no member '%s'" % key)
class UnionType(CythonType):
def __init__(self, **data):
if len(data) > 0:
raise AttributeError("Union can only store one field at a time.")
for key, value in data.iteritems():
setattr(self, key, value)
def __setattr__(self, key, value):
if key in '__dict__':
CythonType.__setattr__(self, key, value)
elif key in self._members:
self.__dict__ = {key: cast(self._members[key], value)}
else:
raise AttributeError("Union has no member '%s'" % key)
def pointer(basetype):
class PointerInstance(PointerType):
_basetype = basetype
return PointerInstance
def array(basetype, n):
class ArrayInstance(ArrayType):
_basetype = basetype
_n = n
return ArrayInstance
def struct(**members):
class StructInstance(StructType):
_members = members
for key in members:
setattr(StructInstance, key, None)
return StructInstance
def union(**members):
class UnionInstance(UnionType):
_members = members
for key in members:
setattr(UnionInstance, key, None)
return UnionInstance
class typedef(CythonType):
def __init__(self, type):
self._basetype = type
def __call__(self, value=None):
if value is not None:
value = cast(self._basetype, value)
return value
py_int = int
try:
py_long = long
except NameError: # Py3
py_long = int
py_float = float
py_complex = complex
try:
# Python 3
from builtins import set, frozenset
except ImportError:
try:
# Python 2.4+
from __builtin__ import set, frozenset
except ImportError:
# Py 2.3
from sets import Set as set, ImmutableSet as frozenset
# Predefined types
int_types = ['char', 'short', 'Py_UNICODE', 'int', 'long', 'longlong', 'Py_ssize_t', 'size_t']
float_types = ['longdouble', 'double', 'float']
complex_types = ['longdoublecomplex', 'doublecomplex', 'floatcomplex', 'complex']
other_types = ['bint', 'void']
gs = globals()
for name in int_types:
gs[name] = typedef(py_int)
if name != 'Py_UNICODE' and not name.endswith('size_t'):
gs['u'+name] = typedef(py_int)
gs['s'+name] = typedef(py_int)
for name in float_types:
gs[name] = typedef(py_float)
for name in complex_types:
gs[name] = typedef(py_complex)
bint = typedef(bool)
void = typedef(int)
for t in int_types + float_types + complex_types + other_types:
for i in range(1, 4):
gs["%s_%s" % ('p'*i, t)] = globals()[t]._pointer(i)
void = typedef(None)
NULL = None
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/StringIOTree.py 0000664 0000000 0000000 00000005415 11446142532 0024105 0 ustar 00root root 0000000 0000000 from cStringIO import StringIO
class StringIOTree(object):
"""
See module docs.
"""
def __init__(self, stream=None):
self.prepended_children = []
if stream is None:
stream = StringIO()
self.stream = stream
self.write = stream.write
def getvalue(self):
content = [x.getvalue() for x in self.prepended_children]
content.append(self.stream.getvalue())
return "".join(content)
def copyto(self, target):
"""Potentially cheaper than getvalue as no string concatenation
needs to happen."""
for child in self.prepended_children:
child.copyto(target)
stream_content = self.stream.getvalue()
if stream_content:
target.write(stream_content)
def commit(self):
# Save what we have written until now so that the buffer
# itself is empty -- this makes it ready for insertion
if self.stream.tell():
self.prepended_children.append(StringIOTree(self.stream))
self.stream = StringIO()
self.write = self.stream.write
def insert(self, iotree):
"""
Insert a StringIOTree (and all of its contents) at this location.
Further writing to self appears after what is inserted.
"""
self.commit()
self.prepended_children.append(iotree)
def insertion_point(self):
"""
Returns a new StringIOTree, which is left behind at the current position
(it what is written to the result will appear right before whatever is
next written to self).
Calling getvalue() or copyto() on the result will only return the
contents written to it.
"""
# Save what we have written until now
# This is so that getvalue on the result doesn't include it.
self.commit()
# Construct the new forked object to return
other = StringIOTree()
self.prepended_children.append(other)
return other
__doc__ = r"""
Implements a buffer with insertion points. When you know you need to
"get back" to a place and write more later, simply call insertion_point()
at that spot and get a new StringIOTree object that is "left behind".
EXAMPLE:
>>> a = StringIOTree()
>>> a.write('first\n')
>>> b = a.insertion_point()
>>> a.write('third\n')
>>> b.write('second\n')
>>> a.getvalue().split()
['first', 'second', 'third']
>>> c = b.insertion_point()
>>> d = c.insertion_point()
>>> d.write('alpha\n')
>>> b.write('gamma\n')
>>> c.write('beta\n')
>>> b.getvalue().split()
['second', 'alpha', 'beta', 'gamma']
>>> i = StringIOTree()
>>> d.insert(i)
>>> i.write('inserted\n')
>>> out = StringIO()
>>> a.copyto(out)
>>> out.getvalue().split()
['first', 'second', 'alpha', 'inserted', 'beta', 'gamma', 'third']
"""
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/TestUtils.py 0000664 0000000 0000000 00000016357 11446142532 0023536 0 ustar 00root root 0000000 0000000 import Cython.Compiler.Errors as Errors
from Cython.CodeWriter import CodeWriter
from Cython.Compiler.ModuleNode import ModuleNode
import Cython.Compiler.Main as Main
from Cython.Compiler.TreeFragment import TreeFragment, strip_common_indent
from Cython.Compiler.Visitor import TreeVisitor, VisitorTransform
from Cython.Compiler import TreePath
import unittest
import os, sys
import tempfile
class NodeTypeWriter(TreeVisitor):
def __init__(self):
super(NodeTypeWriter, self).__init__()
self._indents = 0
self.result = []
def visit_Node(self, node):
if len(self.access_path) == 0:
name = u"(root)"
else:
tip = self.access_path[-1]
if tip[2] is not None:
name = u"%s[%d]" % tip[1:3]
else:
name = tip[1]
self.result.append(u" " * self._indents +
u"%s: %s" % (name, node.__class__.__name__))
self._indents += 1
self.visitchildren(node)
self._indents -= 1
def treetypes(root):
"""Returns a string representing the tree by class names.
There's a leading and trailing whitespace so that it can be
compared by simple string comparison while still making test
cases look ok."""
w = NodeTypeWriter()
w.visit(root)
return u"\n".join([u""] + w.result + [u""])
class CythonTest(unittest.TestCase):
def setUp(self):
self.listing_file = Errors.listing_file
self.echo_file = Errors.echo_file
Errors.listing_file = Errors.echo_file = None
def tearDown(self):
Errors.listing_file = self.listing_file
Errors.echo_file = self.echo_file
def assertLines(self, expected, result):
"Checks that the given strings or lists of strings are equal line by line"
if not isinstance(expected, list): expected = expected.split(u"\n")
if not isinstance(result, list): result = result.split(u"\n")
for idx, (expected_line, result_line) in enumerate(zip(expected, result)):
self.assertEqual(expected_line, result_line, "Line %d:\nExp: %s\nGot: %s" % (idx, expected_line, result_line))
self.assertEqual(len(expected), len(result),
"Unmatched lines. Got:\n%s\nExpected:\n%s" % ("\n".join(expected), u"\n".join(result)))
def codeToLines(self, tree):
writer = CodeWriter()
writer.write(tree)
return writer.result.lines
def codeToString(self, tree):
return "\n".join(self.codeToLines(tree))
def assertCode(self, expected, result_tree):
result_lines = self.codeToLines(result_tree)
expected_lines = strip_common_indent(expected.split("\n"))
for idx, (line, expected_line) in enumerate(zip(result_lines, expected_lines)):
self.assertEqual(expected_line, line, "Line %d:\nGot: %s\nExp: %s" % (idx, line, expected_line))
self.assertEqual(len(result_lines), len(expected_lines),
"Unmatched lines. Got:\n%s\nExpected:\n%s" % ("\n".join(result_lines), expected))
def assertNodeExists(self, path, result_tree):
self.assertNotEqual(TreePath.find_first(result_tree, path), None,
"Path '%s' not found in result tree" % path)
def fragment(self, code, pxds={}, pipeline=[]):
"Simply create a tree fragment using the name of the test-case in parse errors."
name = self.id()
if name.startswith("__main__."): name = name[len("__main__."):]
name = name.replace(".", "_")
return TreeFragment(code, name, pxds, pipeline=pipeline)
def treetypes(self, root):
return treetypes(root)
def should_fail(self, func, exc_type=Exception):
"""Calls "func" and fails if it doesn't raise the right exception
(any exception by default). Also returns the exception in question.
"""
try:
func()
self.fail("Expected an exception of type %r" % exc_type)
except exc_type, e:
self.assert_(isinstance(e, exc_type))
return e
def should_not_fail(self, func):
"""Calls func and succeeds if and only if no exception is raised
(i.e. converts exception raising into a failed testcase). Returns
the return value of func."""
try:
return func()
except:
self.fail(str(sys.exc_info()[1]))
class TransformTest(CythonTest):
"""
Utility base class for transform unit tests. It is based around constructing
test trees (either explicitly or by parsing a Cython code string); running
the transform, serialize it using a customized Cython serializer (with
special markup for nodes that cannot be represented in Cython),
and do a string-comparison line-by-line of the result.
To create a test case:
- Call run_pipeline. The pipeline should at least contain the transform you
are testing; pyx should be either a string (passed to the parser to
create a post-parse tree) or a node representing input to pipeline.
The result will be a transformed result.
- Check that the tree is correct. If wanted, assertCode can be used, which
takes a code string as expected, and a ModuleNode in result_tree
(it serializes the ModuleNode to a string and compares line-by-line).
All code strings are first stripped for whitespace lines and then common
indentation.
Plans: One could have a pxd dictionary parameter to run_pipeline.
"""
def run_pipeline(self, pipeline, pyx, pxds={}):
tree = self.fragment(pyx, pxds).root
# Run pipeline
for T in pipeline:
tree = T(tree)
return tree
class TreeAssertVisitor(VisitorTransform):
# actually, a TreeVisitor would be enough, but this needs to run
# as part of the compiler pipeline
def visit_CompilerDirectivesNode(self, node):
directives = node.directives
if 'test_assert_path_exists' in directives:
for path in directives['test_assert_path_exists']:
if TreePath.find_first(node, path) is None:
Errors.error(
node.pos,
"Expected path '%s' not found in result tree" % path)
if 'test_fail_if_path_exists' in directives:
for path in directives['test_fail_if_path_exists']:
if TreePath.find_first(node, path) is not None:
Errors.error(
node.pos,
"Unexpected path '%s' found in result tree" % path)
self.visitchildren(node)
return node
visit_Node = VisitorTransform.recurse_to_children
def unpack_source_tree(tree_file, dir=None):
if dir is None:
dir = tempfile.mkdtemp()
header = []
cur_file = None
for line in open(tree_file).readlines():
if line[:5] == '#####':
filename = line.strip().strip('#').strip().replace('/', os.path.sep)
path = os.path.join(dir, filename)
if not os.path.exists(os.path.dirname(path)):
os.makedirs(os.path.dirname(path))
cur_file = open(path, 'w')
elif cur_file is not None:
cur_file.write(line)
else:
header.append(line)
return dir, ''.join(header)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Tests/ 0000775 0000000 0000000 00000000000 11446142532 0022312 5 ustar 00root root 0000000 0000000 cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Tests/TestCodeWriter.py 0000664 0000000 0000000 00000004454 11446142532 0025602 0 ustar 00root root 0000000 0000000 from Cython.TestUtils import CythonTest
class TestCodeWriter(CythonTest):
# CythonTest uses the CodeWriter heavily, so do some checking by
# roundtripping Cython code through the test framework.
# Note that this test is dependant upon the normal Cython parser
# to generate the input trees to the CodeWriter. This save *a lot*
# of time; better to spend that time writing other tests than perfecting
# this one...
# Whitespace is very significant in this process:
# - always newline on new block (!)
# - indent 4 spaces
# - 1 space around every operator
def t(self, codestr):
self.assertCode(codestr, self.fragment(codestr).root)
def test_print(self):
self.t(u"""
print x, y
print x + y ** 2
print x, y, z,
""")
def test_if(self):
self.t(u"if x:\n pass")
def test_ifelifelse(self):
self.t(u"""
if x:
pass
elif y:
pass
elif z + 34 ** 34 - 2:
pass
else:
pass
""")
def test_def(self):
self.t(u"""
def f(x, y, z):
pass
def f(x = 34, y = 54, z):
pass
""")
def test_longness_and_signedness(self):
self.t(u"def f(unsigned long long long long long int y):\n pass")
def test_signed_short(self):
self.t(u"def f(signed short int y):\n pass")
def test_typed_args(self):
self.t(u"def f(int x, unsigned long int y):\n pass")
def test_cdef_var(self):
self.t(u"""
cdef int hello
cdef int hello = 4, x = 3, y, z
""")
def test_for_loop(self):
self.t(u"""
for x, y, z in f(g(h(34) * 2) + 23):
print x, y, z
else:
print 43
""")
def test_inplace_assignment(self):
self.t(u"x += 43")
def test_attribute(self):
self.t(u"a.x")
if __name__ == "__main__":
import unittest
unittest.main()
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Tests/__init__.py 0000664 0000000 0000000 00000000007 11446142532 0024420 0 ustar 00root root 0000000 0000000 #empty
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Tests/xmlrunner.py 0000664 0000000 0000000 00000032754 11446142532 0024731 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
"""unittest-xml-reporting is a PyUnit-based TestRunner that can export test
results to XML files that can be consumed by a wide range of tools, such as
build systems, IDEs and Continuous Integration servers.
This module provides the XMLTestRunner class, which is heavily based on the
default TextTestRunner. This makes the XMLTestRunner very simple to use.
The script below, adapted from the unittest documentation, shows how to use
XMLTestRunner in a very simple way. In fact, the only difference between this
script and the original one is the last line:
import random
import unittest
import xmlrunner
class TestSequenceFunctions(unittest.TestCase):
def setUp(self):
self.seq = range(10)
def test_shuffle(self):
# make sure the shuffled sequence does not lose any elements
random.shuffle(self.seq)
self.seq.sort()
self.assertEqual(self.seq, range(10))
def test_choice(self):
element = random.choice(self.seq)
self.assert_(element in self.seq)
def test_sample(self):
self.assertRaises(ValueError, random.sample, self.seq, 20)
for element in random.sample(self.seq, 5):
self.assert_(element in self.seq)
if __name__ == '__main__':
unittest.main(testRunner=xmlrunner.XMLTestRunner(output='test-reports'))
"""
import os
import sys
import time
from unittest import TestResult, _TextTestResult, TextTestRunner
from cStringIO import StringIO
class _TestInfo(object):
"""This class is used to keep useful information about the execution of a
test method.
"""
# Possible test outcomes
(SUCCESS, FAILURE, ERROR) = range(3)
def __init__(self, test_result, test_method, outcome=SUCCESS, err=None):
"Create a new instance of _TestInfo."
self.test_result = test_result
self.test_method = test_method
self.outcome = outcome
self.err = err
def get_elapsed_time(self):
"""Return the time that shows how long the test method took to
execute.
"""
return self.test_result.stop_time - self.test_result.start_time
def get_description(self):
"Return a text representation of the test method."
return self.test_result.getDescription(self.test_method)
def get_error_info(self):
"""Return a text representation of an exception thrown by a test
method.
"""
if not self.err:
return ''
if sys.version_info < (2,4):
return self.test_result._exc_info_to_string(self.err)
else:
return self.test_result._exc_info_to_string(
self.err, self.test_method)
class _XMLTestResult(_TextTestResult):
"""A test result class that can express test results in a XML report.
Used by XMLTestRunner.
"""
def __init__(self, stream=sys.stderr, descriptions=1, verbosity=1, \
elapsed_times=True):
"Create a new instance of _XMLTestResult."
_TextTestResult.__init__(self, stream, descriptions, verbosity)
self.successes = []
self.callback = None
self.elapsed_times = elapsed_times
def _prepare_callback(self, test_info, target_list, verbose_str,
short_str):
"""Append a _TestInfo to the given target list and sets a callback
method to be called by stopTest method.
"""
target_list.append(test_info)
def callback():
"""This callback prints the test method outcome to the stream,
as well as the elapsed time.
"""
# Ignore the elapsed times for a more reliable unit testing
if not self.elapsed_times:
self.start_time = self.stop_time = 0
if self.showAll:
self.stream.writeln('(%.3fs) %s' % \
(test_info.get_elapsed_time(), verbose_str))
elif self.dots:
self.stream.write(short_str)
self.callback = callback
def startTest(self, test):
"Called before execute each test method."
self.start_time = time.time()
TestResult.startTest(self, test)
if self.showAll:
self.stream.write(' ' + self.getDescription(test))
self.stream.write(" ... ")
def stopTest(self, test):
"Called after execute each test method."
_TextTestResult.stopTest(self, test)
self.stop_time = time.time()
if self.callback and callable(self.callback):
self.callback()
self.callback = None
def addSuccess(self, test):
"Called when a test executes successfully."
self._prepare_callback(_TestInfo(self, test), \
self.successes, 'OK', '.')
def addFailure(self, test, err):
"Called when a test method fails."
self._prepare_callback(_TestInfo(self, test, _TestInfo.FAILURE, err), \
self.failures, 'FAIL', 'F')
def addError(self, test, err):
"Called when a test method raises an error."
self._prepare_callback(_TestInfo(self, test, _TestInfo.ERROR, err), \
self.errors, 'ERROR', 'E')
def printErrorList(self, flavour, errors):
"Write some information about the FAIL or ERROR to the stream."
for test_info in errors:
self.stream.writeln(self.separator1)
self.stream.writeln('%s [%.3fs]: %s' % \
(flavour, test_info.get_elapsed_time(), \
test_info.get_description()))
self.stream.writeln(self.separator2)
self.stream.writeln('%s' % test_info.get_error_info())
def _get_info_by_testcase(self):
"""This method organizes test results by TestCase module. This
information is used during the report generation, where a XML report
will be generated for each TestCase.
"""
tests_by_testcase = {}
for tests in (self.successes, self.failures, self.errors):
for test_info in tests:
testcase = type(test_info.test_method)
# Ignore module name if it is '__main__'
module = testcase.__module__ + '.'
if module == '__main__.':
module = ''
testcase_name = module + testcase.__name__
if not tests_by_testcase.has_key(testcase_name):
tests_by_testcase[testcase_name] = []
tests_by_testcase[testcase_name].append(test_info)
return tests_by_testcase
def _report_testsuite(suite_name, tests, xml_document):
"Appends the testsuite section to the XML document."
testsuite = xml_document.createElement('testsuite')
xml_document.appendChild(testsuite)
testsuite.setAttribute('name', str(suite_name))
testsuite.setAttribute('tests', str(len(tests)))
testsuite.setAttribute('time', '%.3f' % \
sum(map(lambda e: e.get_elapsed_time(), tests)))
failures = filter(lambda e: e.outcome==_TestInfo.FAILURE, tests)
testsuite.setAttribute('failures', str(len(failures)))
errors = filter(lambda e: e.outcome==_TestInfo.ERROR, tests)
testsuite.setAttribute('errors', str(len(errors)))
return testsuite
_report_testsuite = staticmethod(_report_testsuite)
def _report_testcase(suite_name, test_result, xml_testsuite, xml_document):
"Appends a testcase section to the XML document."
testcase = xml_document.createElement('testcase')
xml_testsuite.appendChild(testcase)
testcase.setAttribute('classname', str(suite_name))
testcase.setAttribute('name', test_result.test_method.shortDescription()
or getattr(test_result.test_method, '_testMethodName',
str(test_result.test_method)))
testcase.setAttribute('time', '%.3f' % test_result.get_elapsed_time())
if (test_result.outcome != _TestInfo.SUCCESS):
elem_name = ('failure', 'error')[test_result.outcome-1]
failure = xml_document.createElement(elem_name)
testcase.appendChild(failure)
failure.setAttribute('type', str(test_result.err[0].__name__))
failure.setAttribute('message', str(test_result.err[1]))
error_info = test_result.get_error_info()
failureText = xml_document.createCDATASection(error_info)
failure.appendChild(failureText)
_report_testcase = staticmethod(_report_testcase)
def _report_output(test_runner, xml_testsuite, xml_document):
"Appends the system-out and system-err sections to the XML document."
systemout = xml_document.createElement('system-out')
xml_testsuite.appendChild(systemout)
stdout = test_runner.stdout.getvalue()
systemout_text = xml_document.createCDATASection(stdout)
systemout.appendChild(systemout_text)
systemerr = xml_document.createElement('system-err')
xml_testsuite.appendChild(systemerr)
stderr = test_runner.stderr.getvalue()
systemerr_text = xml_document.createCDATASection(stderr)
systemerr.appendChild(systemerr_text)
_report_output = staticmethod(_report_output)
def generate_reports(self, test_runner):
"Generates the XML reports to a given XMLTestRunner object."
from xml.dom.minidom import Document
all_results = self._get_info_by_testcase()
if type(test_runner.output) == str and not \
os.path.exists(test_runner.output):
os.makedirs(test_runner.output)
for suite, tests in all_results.items():
doc = Document()
# Build the XML file
testsuite = _XMLTestResult._report_testsuite(suite, tests, doc)
for test in tests:
_XMLTestResult._report_testcase(suite, test, testsuite, doc)
_XMLTestResult._report_output(test_runner, testsuite, doc)
xml_content = doc.toprettyxml(indent='\t')
if type(test_runner.output) is str:
report_file = open('%s%sTEST-%s.xml' % \
(test_runner.output, os.sep, suite), 'w')
try:
report_file.write(xml_content)
finally:
report_file.close()
else:
# Assume that test_runner.output is a stream
test_runner.output.write(xml_content)
class XMLTestRunner(TextTestRunner):
"""A test runner class that outputs the results in JUnit like XML files.
"""
def __init__(self, output='.', stream=sys.stderr, descriptions=True, \
verbose=False, elapsed_times=True):
"Create a new instance of XMLTestRunner."
verbosity = (1, 2)[verbose]
TextTestRunner.__init__(self, stream, descriptions, verbosity)
self.output = output
self.elapsed_times = elapsed_times
def _make_result(self):
"""Create the TestResult object which will be used to store
information about the executed tests.
"""
return _XMLTestResult(self.stream, self.descriptions, \
self.verbosity, self.elapsed_times)
def _patch_standard_output(self):
"""Replace the stdout and stderr streams with string-based streams
in order to capture the tests' output.
"""
(self.old_stdout, self.old_stderr) = (sys.stdout, sys.stderr)
(sys.stdout, sys.stderr) = (self.stdout, self.stderr) = \
(StringIO(), StringIO())
def _restore_standard_output(self):
"Restore the stdout and stderr streams."
(sys.stdout, sys.stderr) = (self.old_stdout, self.old_stderr)
def run(self, test):
"Run the given test case or test suite."
try:
# Prepare the test execution
self._patch_standard_output()
result = self._make_result()
# Print a nice header
self.stream.writeln()
self.stream.writeln('Running tests...')
self.stream.writeln(result.separator2)
# Execute tests
start_time = time.time()
test(result)
stop_time = time.time()
time_taken = stop_time - start_time
# Print results
result.printErrors()
self.stream.writeln(result.separator2)
run = result.testsRun
self.stream.writeln("Ran %d test%s in %.3fs" %
(run, run != 1 and "s" or "", time_taken))
self.stream.writeln()
# Error traces
if not result.wasSuccessful():
self.stream.write("FAILED (")
failed, errored = (len(result.failures), len(result.errors))
if failed:
self.stream.write("failures=%d" % failed)
if errored:
if failed:
self.stream.write(", ")
self.stream.write("errors=%d" % errored)
self.stream.writeln(")")
else:
self.stream.writeln("OK")
# Generate reports
self.stream.writeln()
self.stream.writeln('Generating XML reports...')
result.generate_reports(self)
finally:
self._restore_standard_output()
return result
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/Utils.py 0000664 0000000 0000000 00000015355 11446142532 0022673 0 ustar 00root root 0000000 0000000 #
# Cython -- Things that don't belong
# anywhere else in particular
#
import os, sys, re, codecs
def replace_suffix(path, newsuf):
base, _ = os.path.splitext(path)
return base + newsuf
def open_new_file(path):
if os.path.exists(path):
# Make sure to create a new file here so we can
# safely hard link the output files.
os.unlink(path)
# we use the ISO-8859-1 encoding here because we only write pure
# ASCII strings or (e.g. for file names) byte encoded strings as
# Unicode, so we need a direct mapping from the first 256 Unicode
# characters to a byte sequence, which ISO-8859-1 provides
return codecs.open(path, "w", encoding="ISO-8859-1")
def castrate_file(path, st):
# Remove junk contents from an output file after a
# failed compilation.
# Also sets access and modification times back to
# those specified by st (a stat struct).
try:
f = open_new_file(path)
except EnvironmentError:
pass
else:
f.write(
"#error Do not use this file, it is the result of a failed Cython compilation.\n")
f.close()
if st:
os.utime(path, (st.st_atime, st.st_mtime-1))
def modification_time(path):
st = os.stat(path)
return st.st_mtime
def file_newer_than(path, time):
ftime = modification_time(path)
return ftime > time
def path_exists(path):
# try on the filesystem first
if os.path.exists(path):
return True
# figure out if a PEP 302 loader is around
try:
loader = __loader__
# XXX the code below assumes as 'zipimport.zipimporter' instance
# XXX should be easy to generalize, but too lazy right now to write it
if path.startswith(loader.archive):
nrmpath = os.path.normpath(path)
arcname = nrmpath[len(loader.archive)+1:]
try:
loader.get_data(arcname)
return True
except IOError:
return False
except NameError:
pass
return False
# file name encodings
def decode_filename(filename):
if isinstance(filename, unicode):
return filename
try:
filename_encoding = sys.getfilesystemencoding()
if filename_encoding is None:
filename_encoding = sys.getdefaultencoding()
filename = filename.decode(filename_encoding)
except UnicodeDecodeError:
pass
return filename
# support for source file encoding detection
_match_file_encoding = re.compile(u"coding[:=]\s*([-\w.]+)").search
def detect_file_encoding(source_filename):
# PEPs 263 and 3120
f = open_source_file(source_filename, encoding="UTF-8", error_handling='ignore')
try:
chars = []
for i in range(2):
c = f.read(1)
while c and c != u'\n':
chars.append(c)
c = f.read(1)
encoding = _match_file_encoding(u''.join(chars))
if encoding:
return encoding.group(1)
finally:
f.close()
return "UTF-8"
normalise_newlines = re.compile(u'\r\n?|\n').sub
class NormalisedNewlineStream(object):
"""The codecs module doesn't provide universal newline support.
This class is used as a stream wrapper that provides this
functionality. The new 'io' in Py2.6+/3.x supports this out of the
box.
"""
def __init__(self, stream):
# let's assume .read() doesn't change
self._read = stream.read
self.close = stream.close
self.encoding = getattr(stream, 'encoding', 'UTF-8')
def read(self, count):
data = self._read(count)
if u'\r' not in data:
return data
if data.endswith(u'\r'):
# may be missing a '\n'
data += self._read(1)
return normalise_newlines(u'\n', data)
def readlines(self):
content = []
data = self.read(0x1000)
while data:
content.append(data)
data = self.read(0x1000)
return u''.join(content).split(u'\n')
io = None
if sys.version_info >= (2,6):
try:
import io
except ImportError:
pass
def open_source_file(source_filename, mode="r",
encoding=None, error_handling=None,
require_normalised_newlines=True):
if encoding is None:
encoding = detect_file_encoding(source_filename)
#
try:
loader = __loader__
if source_filename.startswith(loader.archive):
return open_source_from_loader(
loader, source_filename,
encoding, error_handling,
require_normalised_newlines)
except (NameError, AttributeError):
pass
#
if io is not None:
return io.open(source_filename, mode=mode,
encoding=encoding, errors=error_handling)
else:
# codecs module doesn't have universal newline support
stream = codecs.open(source_filename, mode=mode,
encoding=encoding, errors=error_handling)
if require_normalised_newlines:
stream = NormalisedNewlineStream(stream)
return stream
def open_source_from_loader(loader,
source_filename,
encoding=None, error_handling=None,
require_normalised_newlines=True):
nrmpath = os.path.normpath(source_filename)
arcname = nrmpath[len(loader.archive)+1:]
data = loader.get_data(arcname)
if io is not None:
return io.TextIOWrapper(io.BytesIO(data),
encoding=encoding,
errors=error_handling)
else:
try:
import cStringIO as StringIO
except ImportError:
import StringIO
reader = codecs.getreader(encoding)
stream = reader(StringIO.StringIO(data))
if require_normalised_newlines:
stream = NormalisedNewlineStream(stream)
return stream
def str_to_number(value):
# note: this expects a string as input that was accepted by the
# parser already
if len(value) < 2:
value = int(value, 0)
elif value[0] == '0':
if value[1] in 'xX':
# hex notation ('0x1AF')
value = int(value[2:], 16)
elif value[1] in 'oO':
# Py3 octal notation ('0o136')
value = int(value[2:], 8)
elif value[1] in 'bB':
# Py3 binary notation ('0b101')
value = int(value[2:], 2)
else:
# Py2 octal notation ('0136')
value = int(value, 8)
else:
value = int(value, 0)
return value
def long_literal(value):
if isinstance(value, basestring):
value = str_to_number(value)
return not -2**31 <= value < 2**31
def none_or_sub(s, data):
if s is None:
return s
else:
return s % data
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Cython/__init__.py 0000664 0000000 0000000 00000000142 11446142532 0023316 0 ustar 00root root 0000000 0000000 # Void cython.* directives (for case insensitive operating systems).
from Cython.Shadow import *
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/ 0000775 0000000 0000000 00000000000 11446142532 0021013 5 ustar 00root root 0000000 0000000 cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/Makefile 0000664 0000000 0000000 00000000432 11446142532 0022452 0 ustar 00root root 0000000 0000000 all:
python Setup.py build_ext --inplace
test: all
python run_primes.py 20
python run_numeric_demo.py
python run_spam.py
cd callback; $(MAKE) test
clean:
@echo Cleaning Demos
@rm -f *.c *.o *.so *~ core
@rm -rf build
@cd callback; $(MAKE) clean
@cd embed; $(MAKE) clean
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/Makefile.nodistutils 0000664 0000000 0000000 00000000606 11446142532 0025035 0 ustar 00root root 0000000 0000000 PYHOME = $(HOME)/pkg/python/version
PYINCLUDE = \
-I$(PYHOME)/include/python2.2 \
-I$(PYHOME)/$(ARCH)/include/python2.2
%.c: %.pyx
../bin/cython $<
%.o: %.c
gcc -c -fPIC $(PYINCLUDE) $<
%.so: %.o
gcc -shared $< -lm -o $@
all: primes.so spam.so numeric_demo.so
clean:
@echo Cleaning Demos
@rm -f *.c *.o *.so *~ core core.*
@cd callback; $(MAKE) clean
@cd embed; $(MAKE) clean
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/callback/ 0000775 0000000 0000000 00000000000 11446142532 0022547 5 ustar 00root root 0000000 0000000 cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/callback/Makefile 0000664 0000000 0000000 00000000243 11446142532 0024206 0 ustar 00root root 0000000 0000000 all:
python Setup.py build_ext --inplace
test: all
python run_cheese.py
clean:
@echo Cleaning Demos/callback
@rm -f cheese.c *.o *.so *~ core
@rm -rf build
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/callback/Makefile.nodistutils 0000664 0000000 0000000 00000000503 11446142532 0026565 0 ustar 00root root 0000000 0000000 PYHOME = $(HOME)/pkg/python/version
PYINCLUDE = \
-I$(PYHOME)/include/python2.2 \
-I$(PYHOME)/$(ARCH)/include/python2.2
%.c: %.pyx
../../bin/cython $<
%.o: %.c
gcc -c -fPIC $(PYINCLUDE) $<
%.so: %.o
gcc -shared $< -lm -o $@
all: cheese.so
clean:
@echo Cleaning Demos/callback
@rm -f *.c *.o *.so *~ core core.*
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/callback/README.txt 0000664 0000000 0000000 00000000527 11446142532 0024251 0 ustar 00root root 0000000 0000000 This example demonstrates how you can wrap a C API
that has a callback interface, so that you can
pass Python functions to it as callbacks.
The files cheesefinder.h and cheesefinder.c
represent the C library to be wrapped.
The file cheese.pyx is the Pyrex module
which wraps it.
The file run_cheese.py demonstrates how to
call the wrapper.
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/callback/Setup.py 0000664 0000000 0000000 00000000412 11446142532 0024216 0 ustar 00root root 0000000 0000000 from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
setup(
name = 'callback',
ext_modules=[
Extension("cheese", ["cheese.pyx", "cheesefinder.c"]),
],
cmdclass = {'build_ext': build_ext}
)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/callback/cheese.pyx 0000664 0000000 0000000 00000000504 11446142532 0024544 0 ustar 00root root 0000000 0000000 #
# Pyrex wrapper for the cheesefinder API
#
cdef extern from "cheesefinder.h":
ctypedef void (*cheesefunc)(char *name, void *user_data)
void find_cheeses(cheesefunc user_func, void *user_data)
def find(f):
find_cheeses(callback, f)
cdef void callback(char *name, void *f):
(f)(name)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/callback/cheesefinder.c 0000664 0000000 0000000 00000000503 11446142532 0025335 0 ustar 00root root 0000000 0000000 /*
* An example of a C API that provides a callback mechanism.
*/
#include "cheesefinder.h"
static char *cheeses[] = {
"cheddar",
"camembert",
"that runny one",
0
};
void find_cheeses(cheesefunc user_func, void *user_data) {
char **p = cheeses;
while (*p) {
user_func(*p, user_data);
++p;
}
}
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/callback/cheesefinder.h 0000664 0000000 0000000 00000000163 11446142532 0025344 0 ustar 00root root 0000000 0000000 typedef void (*cheesefunc)(char *name, void *user_data);
void find_cheeses(cheesefunc user_func, void *user_data);
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/callback/run_cheese.py 0000664 0000000 0000000 00000000150 11446142532 0025235 0 ustar 00root root 0000000 0000000 import cheese
def report_cheese(name):
print("Found cheese: " + name)
cheese.find(report_cheese)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/embed/ 0000775 0000000 0000000 00000000000 11446142532 0022067 5 ustar 00root root 0000000 0000000 cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/embed/Makefile 0000664 0000000 0000000 00000003060 11446142532 0023526 0 ustar 00root root 0000000 0000000 # Makefile for creating our standalone Cython program
PYTHON=python
PYVERSION=$(shell $(PYTHON) -c "import sys; print(sys.version[:3])")
INCDIR=$(shell $(PYTHON) -c "from distutils import sysconfig; print(sysconfig.get_python_inc())")
LIBDIR1=$(shell $(PYTHON) -c "from distutils import sysconfig; print(sysconfig.get_config_var('LIBDIR'))")
LIBDIR2=$(shell $(PYTHON) -c "from distutils import sysconfig; print(sysconfig.get_config_var('LIBPL'))")
STATIC_PYLIB=$(shell $(PYTHON) -c "from distutils import sysconfig; print(sysconfig.get_config_var('LIBRARY'))")
CC=$(shell $(PYTHON) -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('CC'))")
LINKCC=$(shell $(PYTHON) -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('LINKCC'))")
LINKFORSHARED=$(shell $(PYTHON) -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('LINKFORSHARED'))")
LIBS=$(shell $(PYTHON) -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('LIBS'))")
SYSLIBS= $(shell $(PYTHON) -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('SYSLIBS'))")
embedded: embedded.o
$(LINKCC) -o $@ $^ $(LIBDIR1)/$(STATIC_PYLIB) $(LINKFORSHARED) -L$(LIBDIR1) -L$(LIBDIR2) $(LIBS) $(SYSLIBS)
embedded.o: embedded.c
$(CC) -c $^ -I$(INCDIR)
embedded.c: embedded.pyx
@$(PYTHON) ../../cython.py --embed embedded.pyx
all: embedded
clean:
@echo Cleaning Demos/embed
@rm -f *~ *.o *.so core core.* *.c embedded test.output
test: clean all
./embedded > test.output
$(PYTHON) assert_equal.py embedded.output test.output
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/embed/Makefile.msc 0000664 0000000 0000000 00000001755 11446142532 0024320 0 ustar 00root root 0000000 0000000 # Makefile for Microsoft C Compiler, building a DLL
PYVERSION = 2.2
PYHOME = \Python$(PYVERSION:.=)
PYINCLUDE = -I$(PYHOME)\include
PYLIB = /LIBPATH:$(PYHOME)\libs
CFLAGS = $(PYINCLUDE) /Ox /W3 /GX -nologo
.SUFFIXES: .exe .dll .obj .c .cpp .pyx
.pyx.c:
$(PYHOME)\Python.exe ../../cython.py $<
all: main.exe
clean:
del /Q/F *.obj embedded.h embedded.c main.exe embedded.dll embedded.lib embedded.exp
# When linking the DLL we must explicitly list all of the exports
# There doesn't seem to be an easy way to get DL_EXPORT to have the correct definition
# to do the export for us without breaking the importing of symbols from the core
# python library.
embedded.dll: embedded.obj
link /nologo /DLL /INCREMENTAL:NO $(PYLIB) $** /IMPLIB:$*.lib /DEF:<< /OUT:$*.dll
EXPORTS initembedded
EXPORTS spam
<<
main.exe: main.obj embedded.lib
link /nologo $** $(PYLIB) /OUT:main.exe
embedded.h: embedded.c
main.obj: embedded.h
embedded.obj: embedded.c
$(CC) /MD $(CFLAGS) -c $**
embedded.lib: embedded.dll
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/embed/Makefile.msc.static 0000664 0000000 0000000 00000000764 11446142532 0025605 0 ustar 00root root 0000000 0000000 # Makefile for Microsoft compiler statically linking
PYVERSION = 2.2
PYHOME = \Python$(PYVERSION:.=)
PYINCLUDE = -I$(PYHOME)\include
PYLIB = /LIBPATH:$(PYHOME)\libs python22.lib
CFLAGS = $(PYINCLUDE) /Ox /W3 /GX -nologo
.SUFFIXES: .exe .dll .obj .c .cpp .pyx
.pyx.c:
$(PYHOME)\Python.exe ../../pyrexc.py $<
all: main.exe
clean:
-del /Q/F *.obj embedded.h embedded.c main.exe
main.exe: main.obj embedded.obj
link /nologo $** $(PYLIB) /OUT:main.exe
embedded.h: embedded.c
main.obj: embedded.h
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/embed/Makefile.unix 0000664 0000000 0000000 00000000630 11446142532 0024510 0 ustar 00root root 0000000 0000000 # Makefile for creating our standalone Cython program
PYVERSION=2.3
PYPREFIX=/usr
INCLUDES=-I$(PYPREFIX)/include/python$(PYVERSION)
embedded: embedded.o
gcc -o $@ $^ -lpython$(PYVERSION)
embedded.o: embedded.c
gcc -c $^ $(INCLUDES)
embedded.c: embedded.pyx
@python ../../cython.py --embed embedded.pyx
all: embedded
clean:
@echo Cleaning Demos/embed
@rm -f *~ *.o *.so core core.* *.c embedded
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/embed/README 0000664 0000000 0000000 00000000674 11446142532 0022756 0 ustar 00root root 0000000 0000000 This example demonstrates how Pyrex-generated code
can be called directly from a main program written in C.
In this example, the module's initialisation function
(called "initembedded", since the module is called
"embedded") is called explicitly. This is necessary
because the module is not being imported using the
normal Python import mechanism.
The Windows makefiles were contributed by
Duncan Booth .
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/embed/assert_equal.py 0000664 0000000 0000000 00000000217 11446142532 0025131 0 ustar 00root root 0000000 0000000 import sys
if open(sys.argv[1]).read() != open(sys.argv[2]).read():
print "Files differ"
sys.exit(1)
else:
print "Files identical"
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/embed/embedded.output 0000664 0000000 0000000 00000000033 11446142532 0025076 0 ustar 00root root 0000000 0000000 __main__
Hi, I'm embedded.
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/embed/embedded.pyx 0000664 0000000 0000000 00000000160 11446142532 0024357 0 ustar 00root root 0000000 0000000
print __name__
if __name__ == "__main__":
print "Hi, I'm embedded."
else:
print "I'm being imported."
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/freeze/ 0000775 0000000 0000000 00000000000 11446142532 0022273 5 ustar 00root root 0000000 0000000 cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/freeze/Makefile 0000664 0000000 0000000 00000002507 11446142532 0023737 0 ustar 00root root 0000000 0000000 CC = gcc
CYTHON = ../../bin/cython
CYTHON_FREEZE = ../../bin/cython_freeze
PYTHON = python
RST2HTML = rst2html
PY_LDFLAGS = $(shell $(PYTHON) -c 'from distutils.sysconfig import get_config_var as g; import sys; sys.stdout.write(" ".join([g("LINKFORSHARED"), "-L"+g("LIBPL")]) + "\n")')
PY_CPPFLAGS = $(shell $(PYTHON) -c 'from distutils.sysconfig import *; import sys; sys.stdout.write("-I"+get_python_inc() + "\n")')
PY_LDLIBS = $(shell $(PYTHON) -c 'from distutils.sysconfig import get_config_var as g; import sys; sys.stdout.write(" ".join(["-lpython"+g("VERSION"), g("SYSLIBS"), g("LIBS"), g("LOCALMODLIBS")]) + "\n")')
CFLAGS = -fPIC -fno-strict-aliasing -g -O2 -Wall -Wextra
CPPFLAGS = $(PY_CPPFLAGS)
LDFLAGS = $(PY_LDFLAGS)
LDLIBS = $(PY_LDLIBS)
# Name of executable
TARGETS = nCr python
# List of Cython source files, with main module first.
CYTHON_SOURCE = combinatorics.pyx cmath.pyx
CYTHON_SECONDARY = $(CYTHON_SOURCE:.pyx=.c) $(TARGETS:=.c)
all : $(TARGETS)
html : README.html
$(TARGETS) : % : %.o $(CYTHON_SOURCE:.pyx=.o)
nCr.c :
$(CYTHON_FREEZE) $(CYTHON_SOURCE:.pyx=) > $@
python.c :
$(CYTHON_FREEZE) --pymain $(CYTHON_SOURCE:.pyx=) > $@
%.c : %.pyx
$(CYTHON) $(CYTHONFLAGS) $^
%.html : %.txt
$(RST2HTML) $^ $@
clean:
$(RM) *.o $(CYTHON_SECONDARY) $(TARGETS) README.html
.PHONY: clean
.SECONDARY: $(CYTHON_SECONDARY)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/freeze/README.txt 0000664 0000000 0000000 00000006761 11446142532 0024003 0 ustar 00root root 0000000 0000000 NAME
====
cython_freeze - create a C file for embedding Cython modules
SYNOPSIS
========
cython_freeze [-o outfile] [-p] module [...]
DESCRIPTION
===========
**cython_freeze** generates a C source file to embed a Python interpreter
with one or more Cython modules built in. This allows one to create a single
executable from Cython code, without having to have separate shared objects
for each Cython module. A major advantage of this approach is that it allows
debuging with gprof(1), which does not work with shared objects.
Unless ``-p`` is given, the first module's ``__name__`` is set to
``"__main__"`` and is imported on startup; if ``-p`` is given, a normal Python
interpreter is built, with the given modules built into the binary.
Note that this method differs from ``cython --embed``. The ``--embed`` options
modifies the resulting C source file to include a ``main()`` function, so it
can only be used on a single Cython module. The advantage ``--embed`` is
simplicity. This module, on the other hand, can be used with multiple
modules, but it requires another C source file to be created.
OPTIONS
=======
-o FILE, --outfile=FILE write output to FILE instead of standard output
-p, --pymain do not automatically run the first module as __main__
EXAMPLE
=======
In the Demos/freeze directory, there exist two Cython modules:
cmath.pyx
A module that interfaces with the -lm library.
combinatorics.pyx
A module that implements n-choose-r using cmath.
Both modules have the Python idiom ``if __name__ == "__main__"``, which only
execute if that module is the "main" module. If run as main, cmath prints the
factorial of the argument, while combinatorics prints n-choose-r.
The provided Makefile creates an executable, *nCr*, using combinatorics as the
"main" module. It basically performs the following (ignoring the compiler
flags)::
$ cython_freeze combinatorics cmath > nCr.c
$ cython combinatorics.pyx
$ cython cmath.pyx
$ gcc -c nCr.c
$ gcc -c combinatorics.c
$ gcc -c cmath.c
$ gcc nCr.o combinatorics.o cmath.o -o nCr
Because the combinatorics module was listed first, its ``__name__`` is set
to ``"__main__"``, while cmath's is set to ``"cmath"``. The executable now
contains a Python interpreter and both Cython modules. ::
$ ./nCr
USAGE: ./nCr n r
Prints n-choose-r.
$ ./nCr 15812351235 12
5.10028093999e+113
You may wish to build a normal Python interpreter, rather than having one
module as "main". This may happen if you want to use your module from an
interactive shell or from another script, yet you still want it statically
linked so you can profile it with gprof. To do this, add the ``--pymain``
flag to ``cython_freeze``. In the Makefile, the *python* executable is built
like this. ::
$ cython_freeze --pymain combinatorics cmath -o python.c
$ gcc -c python.c
$ gcc python.o combinatorics.o cmath.o -o python
Now ``python`` is a normal Python interpreter, but the cmath and combinatorics
modules will be built into the executable. ::
$ ./python
Python 2.6.2 (release26-maint, Apr 19 2009, 01:58:18)
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import cmath
>>> cmath.factorial(155)
4.7891429014634364e+273
PREREQUISITES
=============
Cython 0.11.2 (or newer, assuming the API does not change)
SEE ALSO
========
* `Python `_
* `Cython `_
* `freeze.py `_
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/freeze/cmath.pyx 0000664 0000000 0000000 00000001077 11446142532 0024136 0 ustar 00root root 0000000 0000000 cdef extern from "math.h":
double c_lgamma "lgamma" (double)
double c_exp "exp" (double)
def exp(n):
"""Return e**n."""
return c_exp(n)
def lfactorial(n):
"""Return an estimate of the log factorial of n."""
return c_lgamma(n+1)
def factorial(n):
"""Return an estimate of the factorial of n."""
return c_exp( c_lgamma(n+1) )
if __name__ == "__main__":
import sys
if len(sys.argv) != 2:
sys.stderr.write("USAGE: %s n\nPrints n!.\n" % sys.argv[0])
sys.exit(2)
n, = map(float, sys.argv[1:])
print factorial(n)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/freeze/combinatorics.pyx 0000664 0000000 0000000 00000000665 11446142532 0025700 0 ustar 00root root 0000000 0000000 import cmath
def nCr(n, r):
"""Return the number of ways to choose r elements of a set of n."""
return cmath.exp( cmath.lfactorial(n) - cmath.lfactorial(r)
- cmath.lfactorial(n-r) )
if __name__ == "__main__":
import sys
if len(sys.argv) != 3:
sys.stderr.write("USAGE: %s n r\nPrints n-choose-r.\n" % sys.argv[0])
sys.exit(2)
n, r = map(float, sys.argv[1:])
print nCr(n, r)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/libraries/ 0000775 0000000 0000000 00000000000 11446142532 0022767 5 ustar 00root root 0000000 0000000 cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/libraries/call_mymath.pyx 0000664 0000000 0000000 00000000133 11446142532 0026020 0 ustar 00root root 0000000 0000000 cdef extern from "mymath.h":
double sinc(double)
def call_sinc(x):
return sinc(x)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/libraries/mymath.c 0000664 0000000 0000000 00000000116 11446142532 0024430 0 ustar 00root root 0000000 0000000 #include "math.h"
double sinc(double x) {
return x == 0 ? 1 : sin(x)/x;
} cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/libraries/mymath.h 0000664 0000000 0000000 00000000025 11446142532 0024434 0 ustar 00root root 0000000 0000000 double sinc(double);
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/libraries/setup.py 0000664 0000000 0000000 00000001602 11446142532 0024500 0 ustar 00root root 0000000 0000000 import os
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
# For demo purposes, we build our own tiny library.
try:
print "building libmymath.a"
assert os.system("gcc -c mymath.c -o mymath.o") == 0
assert os.system("ar rcs libmymath.a mymath.o") == 0
except:
if not os.path.exists("libmymath.a"):
print "Error building external library, please create libmymath.a manually."
sys.exit(1)
# Here is how to use the library built above.
ext_modules=[
Extension("call_mymath",
sources = ["call_mymath.pyx"],
include_dirs = [os.getcwd()], # path to .h file(s)
library_dirs = [os.getcwd()], # path to .a or .so file(s)
libraries = ['mymath'])
]
setup(
name = 'Demos',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules,
)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/numeric_demo.pyx 0000664 0000000 0000000 00000001702 11446142532 0024223 0 ustar 00root root 0000000 0000000 #
# This example demonstrates how to access the internals
# of a Numeric array object.
#
cdef extern from "Numeric/arrayobject.h":
struct PyArray_Descr:
int type_num, elsize
char type
ctypedef class Numeric.ArrayType [object PyArrayObject]:
cdef char *data
cdef int nd
cdef int *dimensions, *strides
cdef object base
cdef PyArray_Descr *descr
cdef int flags
def print_2d_array(ArrayType a):
print "Type:", chr(a.descr.type)
if chr(a.descr.type) <> "f":
raise TypeError("Float array required")
if a.nd <> 2:
raise ValueError("2 dimensional array required")
cdef int nrows, ncols
cdef float *elems, x
nrows = a.dimensions[0]
ncols = a.dimensions[1]
elems = a.data
hyphen = "-"
divider = ("+" + 10 * hyphen) * ncols + "+"
print divider
for row in range(nrows):
for col in range(ncols):
x = elems[row * ncols + col]
print "| %8f" % x,
print "|"
print divider
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/primes.pyx 0000664 0000000 0000000 00000000576 11446142532 0023064 0 ustar 00root root 0000000 0000000 print "starting"
def primes(int kmax):
# cdef int n, k, i
cdef int p[1000]
result = []
if kmax > 1000:
kmax = 1000
k = 0
n = 2
while k < kmax:
i = 0
while i < k and n % p[i] <> 0:
i = i + 1
if i == k:
p[k] = n
k = k + 1
result.append(n)
n = n + 1
return result
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/pyprimes.py 0000664 0000000 0000000 00000000360 11446142532 0023234 0 ustar 00root root 0000000 0000000 def primes(kmax):
p = []
k = 0
n = 2
while k < kmax:
i = 0
while i < k and n % p[i] != 0:
i = i + 1
if i == k:
p.append(n)
k = k + 1
n = n + 1
return p
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/run_numeric_demo.py 0000664 0000000 0000000 00000000176 11446142532 0024723 0 ustar 00root root 0000000 0000000 import Numeric
import numeric_demo
a = Numeric.array([[1.0, 3.5, 8.4], [2.3, 6.6, 4.1]], "f")
numeric_demo.print_2d_array(a)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/run_primes.py 0000664 0000000 0000000 00000000170 11446142532 0023546 0 ustar 00root root 0000000 0000000 import sys
from primes import primes
if len(sys.argv) >= 2:
n = int(sys.argv[1])
else:
n = 1000
print primes(n)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/run_spam.py 0000664 0000000 0000000 00000000176 11446142532 0023215 0 ustar 00root root 0000000 0000000 from spam import Spam
s = Spam()
print "Created:", s
s.set_amount(42)
print "Amount =", s.get_amount()
s.describe()
s = None
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/setup.py 0000664 0000000 0000000 00000001212 11446142532 0022521 0 ustar 00root root 0000000 0000000 import glob
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
try:
from numpy.distutils.misc_util import get_numpy_include_dirs
numpy_include_dirs = get_numpy_include_dirs()
except:
numpy_include_dirs = []
ext_modules=[
Extension("primes", ["primes.pyx"]),
Extension("spam", ["spam.pyx"]),
]
for file in glob.glob("*.pyx"):
if file != "numeric_demo.pyx":
ext_modules.append(Extension(file[:-4], [file], include_dirs = numpy_include_dirs))
setup(
name = 'Demos',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules,
)
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Demos/spam.pyx 0000664 0000000 0000000 00000000566 11446142532 0022524 0 ustar 00root root 0000000 0000000 #
# Example of an extension type.
#
cdef class Spam:
cdef public int amount
def __new__(self):
self.amount = 0
def __dealloc__(self):
print self.amount, "tons of spam is history."
def get_amount(self):
return self.amount
def set_amount(self, new_amount):
self.amount = new_amount
def describe(self):
print self.amount, "tons of spam!"
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Doc/ 0000775 0000000 0000000 00000000000 11446142532 0020451 5 ustar 00root root 0000000 0000000 cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Doc/About.html 0000664 0000000 0000000 00000021176 11446142532 0022420 0 ustar 00root root 0000000 0000000
About Cython
Cython
A language for writing Python extension modules
What is Cython all about?
Cython is a language specially designed for writing Python extension modules.
It's designed to bridge the gap between the nice, high-level, easy-to-use
world of Python and the messy, low-level world of C.
You may be wondering why anyone would want a special language for this.
Python is really easy to extend using C or C++, isn't it? Why not just
write your extension modules in one of those languages?
Well, if you've ever written an extension module for Python, you'll
know that things are not as easy as all that. First of all, there is a
fair bit of boilerplate code to write before you can even get off the ground.
Then you're faced with the problem of converting between Python and C data
types. For the basic types such as numbers and strings this is not too
bad, but anything more elaborate and you're into picking Python objects
apart using the Python/C API calls, which requires you to be meticulous
about maintaining reference counts, checking for errors at every step and
cleaning up properly if anything goes wrong. Any mistakes and you have
a nasty crash that's very difficult to debug.
Various tools have been developed to ease some of the burdens of producing
extension code, of which perhaps SWIG
is the best known. SWIG takes a definition file consisting of a mixture
of C code and specialised declarations, and produces an extension module.
It writes all the boilerplate for you, and in many cases you can use it
without knowing about the Python/C API. But you need to use API calls if
any substantial restructuring of the data is required between Python and
C.
What's more, SWIG gives you no help at all if you want to create a new
built-in Python type. It will generate pure-Python classes which
wrap (in a slightly unsafe manner) pointers to C data structures, but creation
of true extension types is outside its scope.
Another notable attempt at making it easier to extend Python is PyInline
, inspired by a similar facility for Perl. PyInline lets you embed pieces
of C code in the midst of a Python file, and automatically extracts them
and compiles them into an extension. But it only converts the basic types
automatically, and as with SWIG, it doesn't address the creation
of new Python types.
Cython aims to go far beyond what any of these previous tools provides.
Cython deals with the basic types just as easily as SWIG, but it also lets
you write code to convert between arbitrary Python data structures and
arbitrary C data structures, in a simple and natural way, without knowing
anything about the Python/C API. That's right -- nothing at all !
Nor do you have to worry about reference counting or error checking --
it's all taken care of automatically, behind the scenes, just as it is
in interpreted Python code. And what's more, Cython lets you define new
built-in Python types just as easily as you can define new classes
in Python.
Sound too good to be true? Read on and find out how it's done.
The Basics of Cython
The fundamental nature of Cython can be summed up as follows: Cython is
Python with C data types .
Cython is Python: Almost any piece of Python code is also valid
Cython code. (There are a few limitations, but this approximation will serve
for now.) The Cython compiler will convert it into C code which makes equivalent
calls to the Python/C API. In this respect, Cython is similar to the former
Python2C project (to which I would supply a reference except that it no
longer seems to exist).
...with C data types. But Cython is much more than that, because
parameters and variables can be declared to have C data types. Code which
manipulates Python values and C values can be freely intermixed, with conversions
occurring automatically wherever possible. Reference count maintenance
and error checking of Python operations is also automatic, and the full
power of Python's exception handling facilities, including the try-except
and try-finally statements, is available to you -- even in the midst of
manipulating C data.
Here's a small example showing some of what can be done. It's a routine
for finding prime numbers. You tell it how many primes you want, and it
returns them as a Python list.
primes.pyx
1 def primes(int kmax):
2 cdef int n, k, i
3 cdef int p[1000]
4 result = []
5 if kmax > 1000:
6 kmax = 1000
7 k = 0
8 n = 2
9 while k < kmax:
10 i = 0
11 while i < k and n % p[i] <> 0:
12 i = i + 1
13 if i == k:
14 p[k] = n
15 k = k + 1
16 result.append(n)
17 n = n + 1
18 return result
You'll see that it starts out just like a normal Python function definition,
except that the parameter kmax is declared to be of type int
. This means that the object passed will be converted to a C integer (or
a TypeError will be raised if it can't be).
Lines 2 and 3 use the cdef statement to define some local C variables.
Line 4 creates a Python list which will be used to return the result. You'll
notice that this is done exactly the same way it would be in Python. Because
the variable result hasn't been given a type, it is assumed to hold
a Python object.
Lines 7-9 set up for a loop which will test candidate numbers for primeness
until the required number of primes has been found. Lines 11-12, which
try dividing a candidate by all the primes found so far, are of particular
interest. Because no Python objects are referred to, the loop is translated
entirely into C code, and thus runs very fast.
When a prime is found, lines 14-15 add it to the p array for fast access
by the testing loop, and line 16 adds it to the result list. Again, you'll
notice that line 16 looks very much like a Python statement, and in fact
it is, with the twist that the C parameter n is automatically converted
to a Python object before being passed to the append method. Finally,
at line 18, a normal Python return statement returns the result
list.
Compiling primes.pyx with the Cython compiler produces an extension module
which we can try out in the interactive interpreter as follows:
>>> import primes
>>> primes.primes(10)
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
>>>
See, it works! And if you're curious about how much work Cython has saved
you, take a look at the C code generated for this module
.
Language Details
For more about the Cython language, see the Language
Overview .
Future Plans
Cython is not finished. Substantial tasks remaining include:
Support for certain Python language features which are planned but not
yet implemented. See the Limitations
section of the Language Overview for a current
list.
C++ support. This could be a very big can of worms - careful thought required
before going there.
Reading C/C++ header files directly would be very nice, but there are some
severe problems that I will have to find solutions for first, such as what
to do about preprocessor macros. My current thinking is to use a separate
tool to convert .h files into Cython declarations, possibly with some manual
intervention.
cython-29e61a09e5fe337d35bf6cc54e548ca0205e4058/Doc/FAQ.html 0000664 0000000 0000000 00000010742 11446142532 0021752 0 ustar 00root root 0000000 0000000
FAQ.html
Cython FAQ
Contents
How do I call Python/C API routines?
Declare them as C functions inside a cdef extern from block.
Use the type name object for any parameters and return types which
are Python object references. Don't use the word const anywhere.
Here is an example which defines and uses the PyString_FromStringAndSize routine:
cdef extern from "Python.h":
object PyString_FromStringAndSize(char *, int) cdef char buf[42]
my_string = PyString_FromStringAndSize(buf, 42)
How do I convert a C string containing null
bytes to a Python string?
Put in a declaration for the PyString_FromStringAndSize API routine
and use that. See How do I call Python/C API
routines? How do I access the data inside a Numeric
array object?
Use a cdef extern from block to include the Numeric header file
and declare the array object as an external extension type. The following
code illustrates how to do this:
cdef extern from "Numeric/arrayobject.h": struct PyArray_Descr:
int type_num, elsize
char type
ctypedef class Numeric.ArrayType [object PyArrayObject] :
cdef char *data
cdef int nd
cdef int *dimensions,
*strides
cdef object base
cdef PyArray_Descr *descr
cdef int flags
For more information about external extension types, see the "External Extension Types"
section of the "Extension Types" documentation
page.
Cython says my extension type object has no attribute
'rhubarb', but I know it does. What gives?
You're probably trying to access it through a reference which Cython thinks
is a generic Python object. You need to tell Cython that it's a reference
to your extension type by means of a declaration,
for example,
cdef class Vegetables:
cdef int rhubarb
...
cdef Vegetables veg
veg.rhubarb = 42
Also see the "Attributes"
section of the "Extension
Types" documentation page.
Python says my extension type has no method called 'quack', but I know it does. What gives?
You may have declared the method using cdef instead of def . Only functions and methods declared with def are callable from Python code.
---