Commit c8b2401a authored by Robert Bradshaw's avatar Robert Bradshaw

Merge gsoc-danilo C++ code into main branch.

parents c5b12aac 09cbfe82
This diff is collapsed.
...@@ -66,7 +66,7 @@ class Context(object): ...@@ -66,7 +66,7 @@ class Context(object):
# include_directories [string] # include_directories [string]
# future_directives [object] # future_directives [object]
def __init__(self, include_directories, compiler_directives): def __init__(self, include_directories, compiler_directives, cpp=False):
#self.modules = {"__builtin__" : BuiltinScope()} #self.modules = {"__builtin__" : BuiltinScope()}
import Builtin, CythonScope import Builtin, CythonScope
self.modules = {"__builtin__" : Builtin.builtin_scope} self.modules = {"__builtin__" : Builtin.builtin_scope}
...@@ -74,6 +74,7 @@ class Context(object): ...@@ -74,6 +74,7 @@ class Context(object):
self.include_directories = include_directories self.include_directories = include_directories
self.future_directives = set() self.future_directives = set()
self.compiler_directives = compiler_directives self.compiler_directives = compiler_directives
self.cpp = cpp
self.pxds = {} # full name -> node tree self.pxds = {} # full name -> node tree
...@@ -451,6 +452,7 @@ class Context(object): ...@@ -451,6 +452,7 @@ class Context(object):
if not isinstance(source_desc, FileSourceDescriptor): if not isinstance(source_desc, FileSourceDescriptor):
raise RuntimeError("Only file sources for code supported") raise RuntimeError("Only file sources for code supported")
source_filename = Utils.encode_filename(source_desc.filename) source_filename = Utils.encode_filename(source_desc.filename)
scope.cpp = self.cpp
# Parse the given source file and return a parse tree. # Parse the given source file and return a parse tree.
try: try:
f = Utils.open_source_file(source_filename, "rU") f = Utils.open_source_file(source_filename, "rU")
...@@ -540,7 +542,7 @@ def create_default_resultobj(compilation_source, options): ...@@ -540,7 +542,7 @@ def create_default_resultobj(compilation_source, options):
def run_pipeline(source, options, full_module_name = None): def run_pipeline(source, options, full_module_name = None):
# Set up context # Set up context
context = Context(options.include_path, options.compiler_directives) context = Context(options.include_path, options.compiler_directives, options.cplus)
# Set up source object # Set up source object
cwd = os.getcwd() cwd = os.getcwd()
......
...@@ -616,7 +616,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -616,7 +616,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
includes = [] includes = []
for filename in env.include_files: for filename in env.include_files:
# fake decoding of filenames to their original byte sequence # fake decoding of filenames to their original byte sequence
code.putln('#include "%s"' % filename) if filename[0] == '<' and filename[-1] == '>':
code.putln('#include %s' % filename)
else:
code.putln('#include "%s"' % filename)
def generate_filename_table(self, code): def generate_filename_table(self, code):
code.putln("") code.putln("")
......
# #
# Pyrex - Parse tree nodes # Pyrex - Parse tree nodes
# #
...@@ -18,7 +19,7 @@ import PyrexTypes ...@@ -18,7 +19,7 @@ import PyrexTypes
import TypeSlots import TypeSlots
from PyrexTypes import py_object_type, error_type, CFuncType from PyrexTypes import py_object_type, error_type, CFuncType
from Symtab import ModuleScope, LocalScope, GeneratorLocalScope, \ from Symtab import ModuleScope, LocalScope, GeneratorLocalScope, \
StructOrUnionScope, PyClassScope, CClassScope StructOrUnionScope, PyClassScope, CClassScope, CppClassScope
from Cython.Utils import open_new_file, replace_suffix from Cython.Utils import open_new_file, replace_suffix
from Code import UtilityCode from Code import UtilityCode
from StringEncoding import EncodedString, escape_byte_string, split_docstring from StringEncoding import EncodedString, escape_byte_string, split_docstring
...@@ -143,6 +144,15 @@ class Node(object): ...@@ -143,6 +144,15 @@ class Node(object):
def gil_error(self, env=None): def gil_error(self, env=None):
error(self.pos, "%s not allowed without gil" % self.gil_message) 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): def clone_node(self):
"""Clone the node. This is defined as a shallow copy, except for member lists """Clone the node. This is defined as a shallow copy, except for member lists
...@@ -447,7 +457,19 @@ class CPtrDeclaratorNode(CDeclaratorNode): ...@@ -447,7 +457,19 @@ class CPtrDeclaratorNode(CDeclaratorNode):
"Pointer base type cannot be a Python object") "Pointer base type cannot be a Python object")
ptr_type = PyrexTypes.c_ptr_type(base_type) ptr_type = PyrexTypes.c_ptr_type(base_type)
return self.base.analyse(ptr_type, env, nonempty = nonempty) 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): class CArrayDeclaratorNode(CDeclaratorNode):
# base CDeclaratorNode # base CDeclaratorNode
# dimension ExprNode # dimension ExprNode
...@@ -455,6 +477,19 @@ class CArrayDeclaratorNode(CDeclaratorNode): ...@@ -455,6 +477,19 @@ class CArrayDeclaratorNode(CDeclaratorNode):
child_attrs = ["base", "dimension"] child_attrs = ["base", "dimension"]
def analyse(self, base_type, env, nonempty = 0): 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: if self.dimension:
self.dimension.analyse_const_expression(env) self.dimension.analyse_const_expression(env)
if not self.dimension.type.is_int: if not self.dimension.type.is_int:
...@@ -655,6 +690,9 @@ class CBaseTypeNode(Node): ...@@ -655,6 +690,9 @@ class CBaseTypeNode(Node):
pass pass
def analyse_as_type(self, env):
return self.analyse(env)
class CAnalysedBaseTypeNode(Node): class CAnalysedBaseTypeNode(Node):
# type type # type type
...@@ -714,7 +752,12 @@ class CSimpleBaseTypeNode(CBaseTypeNode): ...@@ -714,7 +752,12 @@ class CSimpleBaseTypeNode(CBaseTypeNode):
type = py_object_type type = py_object_type
self.arg_name = self.name self.arg_name = self.name
else: else:
error(self.pos, "'%s' is not a type identifier" % self.name) 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 self.complex:
if not type.is_numeric or type.is_complex: if not type.is_numeric or type.is_complex:
error(self.pos, "can only complexify c numeric types") error(self.pos, "can only complexify c numeric types")
...@@ -725,14 +768,14 @@ class CSimpleBaseTypeNode(CBaseTypeNode): ...@@ -725,14 +768,14 @@ class CSimpleBaseTypeNode(CBaseTypeNode):
else: else:
return PyrexTypes.error_type return PyrexTypes.error_type
class CBufferAccessTypeNode(CBaseTypeNode): class TemplatedTypeNode(CBaseTypeNode):
# After parsing: # After parsing:
# positional_args [ExprNode] List of positional arguments # positional_args [ExprNode] List of positional arguments
# keyword_args DictNode Keyword arguments # keyword_args DictNode Keyword arguments
# base_type_node CBaseTypeNode # base_type_node CBaseTypeNode
# After analysis: # After analysis:
# type PyrexType.BufferType ...containing the right options # type PyrexTypes.BufferType or PyrexTypes.CppClassType ...containing the right options
child_attrs = ["base_type_node", "positional_args", child_attrs = ["base_type_node", "positional_args",
...@@ -742,24 +785,38 @@ class CBufferAccessTypeNode(CBaseTypeNode): ...@@ -742,24 +785,38 @@ class CBufferAccessTypeNode(CBaseTypeNode):
name = None name = None
def analyse(self, env, could_be_name = False): def analyse(self, env, could_be_name = False, base_type = None):
base_type = self.base_type_node.analyse(env) 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_error: return base_type
import Buffer
if base_type.is_cpp_class:
if len(self.keyword_args.key_value_pairs) != 0:
error(self.pos, "c++ templates cannot take keyword arguments");
self.type = PyrexTypes.error_type
else:
template_types = []
for template_node in self.positional_args:
template_types.append(template_node.analyse_as_type(env))
self.type = base_type.specialize_here(self.pos, template_types)
else:
import Buffer
options = Buffer.analyse_buffer_options( options = Buffer.analyse_buffer_options(
self.pos, self.pos,
env, env,
self.positional_args, self.positional_args,
self.keyword_args, self.keyword_args,
base_type.buffer_defaults) base_type.buffer_defaults)
if sys.version_info[0] < 3: if sys.version_info[0] < 3:
# Py 2.x enforces byte strings as keyword arguments ... # Py 2.x enforces byte strings as keyword arguments ...
options = dict([ (name.encode('ASCII'), value) options = dict([ (name.encode('ASCII'), value)
for name, value in options.iteritems() ]) for name, value in options.iteritems() ])
self.type = PyrexTypes.BufferType(base_type, **options) self.type = PyrexTypes.BufferType(base_type, **options)
return self.type return self.type
class CComplexBaseTypeNode(CBaseTypeNode): class CComplexBaseTypeNode(CBaseTypeNode):
...@@ -904,6 +961,46 @@ class CStructOrUnionDefNode(StatNode): ...@@ -904,6 +961,46 @@ class CStructOrUnionDefNode(StatNode):
pass 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 len(self.attributes) != 0:
scope = CppClassScope(self.name, env)
else:
self.attributes = None
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): class CEnumDefNode(StatNode):
# name string or None # name string or None
# cname string or None # cname string or None
...@@ -3391,8 +3488,14 @@ class DelStatNode(StatNode): ...@@ -3391,8 +3488,14 @@ class DelStatNode(StatNode):
def analyse_expressions(self, env): def analyse_expressions(self, env):
for arg in self.args: for arg in self.args:
arg.analyse_target_expression(env, None) arg.analyse_target_expression(env, None)
if not arg.type.is_pyobject: if arg.type.is_pyobject:
error(arg.pos, "Deletion of non-Python object") 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) #arg.release_target_temp(env)
def nogil_check(self, env): def nogil_check(self, env):
...@@ -3406,6 +3509,9 @@ class DelStatNode(StatNode): ...@@ -3406,6 +3509,9 @@ class DelStatNode(StatNode):
for arg in self.args: for arg in self.args:
if arg.type.is_pyobject: if arg.type.is_pyobject:
arg.generate_deletion_code(code) 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 # else error reported earlier
def annotate(self, code): def annotate(self, code):
......
...@@ -128,7 +128,6 @@ class PostParseError(CompileError): pass ...@@ -128,7 +128,6 @@ class PostParseError(CompileError): pass
# error strings checked by unit tests, so define them # 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_CDEF_INCLASS = 'Cannot assign default value to fields in cdef classes, structs or unions'
ERR_BUF_LOCALONLY = 'Buffer types only allowed as function local variables'
ERR_BUF_DEFAULTS = 'Invalid buffer defaults specification (see docs)' ERR_BUF_DEFAULTS = 'Invalid buffer defaults specification (see docs)'
ERR_INVALID_SPECIALATTR_TYPE = 'Special attributes must not have a type declared' ERR_INVALID_SPECIALATTR_TYPE = 'Special attributes must not have a type declared'
class PostParse(CythonTransform): class PostParse(CythonTransform):
...@@ -145,7 +144,7 @@ class PostParse(CythonTransform): ...@@ -145,7 +144,7 @@ class PostParse(CythonTransform):
- Interpret some node structures into Python runtime values. - Interpret some node structures into Python runtime values.
Some nodes take compile-time arguments (currently: Some nodes take compile-time arguments (currently:
CBufferAccessTypeNode[args] and __cythonbufferdefaults__ = {args}), TemplatedTypeNode[args] and __cythonbufferdefaults__ = {args}),
which should be interpreted. This happens in a general way which should be interpreted. This happens in a general way
and other steps should be taken to ensure validity. and other steps should be taken to ensure validity.
...@@ -154,7 +153,7 @@ class PostParse(CythonTransform): ...@@ -154,7 +153,7 @@ class PostParse(CythonTransform):
- For __cythonbufferdefaults__ the arguments are checked for - For __cythonbufferdefaults__ the arguments are checked for
validity. validity.
CBufferAccessTypeNode has its directives interpreted: TemplatedTypeNode has its directives interpreted:
Any first positional argument goes into the "dtype" attribute, Any first positional argument goes into the "dtype" attribute,
any "ndim" keyword argument goes into the "ndim" attribute and any "ndim" keyword argument goes into the "ndim" attribute and
so on. Also it is checked that the directive combination is valid. so on. Also it is checked that the directive combination is valid.
...@@ -243,11 +242,6 @@ class PostParse(CythonTransform): ...@@ -243,11 +242,6 @@ class PostParse(CythonTransform):
self.context.nonfatal_error(e) self.context.nonfatal_error(e)
return None return None
def visit_CBufferAccessTypeNode(self, node):
if not self.scope_type == 'function':
raise PostParseError(node.pos, ERR_BUF_LOCALONLY)
return node
class PxdPostParse(CythonTransform, SkipDeclarations): class PxdPostParse(CythonTransform, SkipDeclarations):
""" """
Basic interpretation/validity checking that should only be Basic interpretation/validity checking that should only be
...@@ -329,7 +323,22 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -329,7 +323,22 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
duplication of functionality has to occur: We manually track cimports duplication of functionality has to occur: We manually track cimports
and which names the "cython" module may have been imported to. and which names the "cython" module may have been imported to.
""" """
special_methods = set(['declare', 'union', 'struct', 'typedef', 'sizeof', 'typeof', 'cast', 'address', 'pointer', 'compiled', 'NULL']) 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,
}
special_methods = set(['declare', 'union', 'struct', 'typedef', 'sizeof', 'cast', 'pointer', 'compiled', 'NULL']
+ unop_method_nodes.keys())
def __init__(self, context, compilation_directive_defaults): def __init__(self, context, compilation_directive_defaults):
super(InterpretCompilerDirectives, self).__init__(context) super(InterpretCompilerDirectives, self).__init__(context)
...@@ -372,18 +381,33 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -372,18 +381,33 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
else: else:
modname = u"cython" modname = u"cython"
self.cython_module_names.add(modname) self.cython_module_names.add(modname)
return node 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")
else:
return node
def visit_FromCImportStatNode(self, node): def visit_FromCImportStatNode(self, node):
if node.module_name == u"cython": if node.module_name.startswith(u"cython."):
is_cython_module = True
submodule = node.module_name[7:] + u"."
elif node.module_name == u"cython":
is_cython_module = True
submodule = u""
else:
is_cython_module = False
if is_cython_module:
newimp = [] newimp = []
for pos, name, as_name, kind in node.imported_names: for pos, name, as_name, kind in node.imported_names:
if (name in Options.directive_types or full_name = submodule + name
name in self.special_methods or if (full_name in Options.directive_types or
PyrexTypes.parse_basic_type(name)): full_name in self.special_methods or
PyrexTypes.parse_basic_type(full_name)):
if as_name is None: if as_name is None:
as_name = name as_name = full_name
self.directive_names[as_name] = name self.directive_names[as_name] = full_name
if kind is not None: if kind is not None:
self.context.nonfatal_error(PostParseError(pos, self.context.nonfatal_error(PostParseError(pos,
"Compiler directive imports must be plain imports")) "Compiler directive imports must be plain imports"))
...@@ -395,13 +419,22 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -395,13 +419,22 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
return node return node
def visit_FromImportStatNode(self, node): def visit_FromImportStatNode(self, node):
if node.module.module_name.value == u"cython": if node.module.module_name.value.startswith(u"cython."):
is_cython_module = True
submodule = node.module.module_name.value[7:] + u"."
elif node.module.module_name.value == u"cython":
is_cython_module = True
submodule = u""
else:
is_cython_module = False
if is_cython_module:
newimp = [] newimp = []
for name, name_node in node.items: for name, name_node in node.items:
if (name in Options.directive_types or full_name = submodule + name
name in self.special_methods or if (full_name in Options.directive_types or
PyrexTypes.parse_basic_type(name)): full_name in self.special_methods or
self.directive_names[name_node.name] = name PyrexTypes.parse_basic_type(full_name)):
self.directive_names[name_node.name] = full_name
else: else:
newimp.append((name, name_node)) newimp.append((name, name_node))
if not newimp: if not newimp:
...@@ -1016,7 +1049,12 @@ class TransformBuiltinMethods(EnvTransform): ...@@ -1016,7 +1049,12 @@ class TransformBuiltinMethods(EnvTransform):
# cython.foo # cython.foo
function = node.function.as_cython_attribute() function = node.function.as_cython_attribute()
if function: if function:
if function == u'cast': 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 == u'cast':
if len(node.args) != 2: if len(node.args) != 2:
error(node.function.pos, u"cast() takes exactly two arguments") error(node.function.pos, u"cast() takes exactly two arguments")
else: else:
...@@ -1034,16 +1072,6 @@ class TransformBuiltinMethods(EnvTransform): ...@@ -1034,16 +1072,6 @@ class TransformBuiltinMethods(EnvTransform):
node = SizeofTypeNode(node.function.pos, arg_type=type) node = SizeofTypeNode(node.function.pos, arg_type=type)
else: else:
node = SizeofVarNode(node.function.pos, operand=node.args[0]) node = SizeofVarNode(node.function.pos, operand=node.args[0])
elif function == 'typeof':
if len(node.args) != 1:
error(node.function.pos, u"typeof() takes exactly one argument")
else:
node = TypeofNode(node.function.pos, operand=node.args[0])
elif function == 'address':
if len(node.args) != 1:
error(node.function.pos, u"address() takes exactly one argument")
else:
node = AmpersandNode(node.function.pos, operand=node.args[0])
elif function == 'cmod': elif function == 'cmod':
if len(node.args) != 2: if len(node.args) != 2:
error(node.function.pos, u"cmod() takes exactly two arguments") error(node.function.pos, u"cmod() takes exactly two arguments")
......
...@@ -28,6 +28,7 @@ cpdef p_typecast(PyrexScanner s) ...@@ -28,6 +28,7 @@ cpdef p_typecast(PyrexScanner s)
cpdef p_sizeof(PyrexScanner s) cpdef p_sizeof(PyrexScanner s)
cpdef p_yield_expression(PyrexScanner s) cpdef p_yield_expression(PyrexScanner s)
cpdef p_power(PyrexScanner s) cpdef p_power(PyrexScanner s)
cpdef p_new_expr(PyrexScanner s)
cpdef p_trailer(PyrexScanner s, node1) cpdef p_trailer(PyrexScanner s, node1)
cpdef p_call(PyrexScanner s, function) cpdef p_call(PyrexScanner s, function)
cpdef p_index(PyrexScanner s, base) cpdef p_index(PyrexScanner s, base)
...@@ -149,3 +150,4 @@ cpdef p_doc_string(PyrexScanner s) ...@@ -149,3 +150,4 @@ cpdef p_doc_string(PyrexScanner s)
cpdef p_code(PyrexScanner s, level= *) cpdef p_code(PyrexScanner s, level= *)
cpdef p_compiler_directive_comments(PyrexScanner s) cpdef p_compiler_directive_comments(PyrexScanner s)
cpdef p_module(PyrexScanner s, pxd, full_module_name) cpdef p_module(PyrexScanner s, pxd, full_module_name)
cpdef p_cpp_class_definition(PyrexScanner s, ctx)
This diff is collapsed.
This diff is collapsed.
...@@ -355,6 +355,14 @@ class PyrexScanner(Scanner): ...@@ -355,6 +355,14 @@ class PyrexScanner(Scanner):
t = "%s %s" % (self.sy, self.systring) t = "%s %s" % (self.sy, self.systring)
print("--- %3d %2d %s" % (line, col, t)) 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): def put_back(self, sy, systring):
self.unread(self.sy, self.systring) self.unread(self.sy, self.systring)
self.sy = sy self.sy = sy
......
This diff is collapsed.
...@@ -21,7 +21,7 @@ class TestBufferParsing(CythonTest): ...@@ -21,7 +21,7 @@ class TestBufferParsing(CythonTest):
def test_basic(self): def test_basic(self):
t = self.parse(u"cdef object[float, 4, ndim=2, foo=foo] x") t = self.parse(u"cdef object[float, 4, ndim=2, foo=foo] x")
bufnode = t.stats[0].base_type bufnode = t.stats[0].base_type
self.assert_(isinstance(bufnode, CBufferAccessTypeNode)) self.assert_(isinstance(bufnode, TemplatedTypeNode))
self.assertEqual(2, len(bufnode.positional_args)) self.assertEqual(2, len(bufnode.positional_args))
# print bufnode.dump() # print bufnode.dump()
# should put more here... # should put more here...
...@@ -65,7 +65,7 @@ class TestBufferOptions(CythonTest): ...@@ -65,7 +65,7 @@ class TestBufferOptions(CythonTest):
vardef = root.stats[0].body.stats[0] vardef = root.stats[0].body.stats[0]
assert isinstance(vardef, CVarDefNode) # use normal assert as this is to validate the test code assert isinstance(vardef, CVarDefNode) # use normal assert as this is to validate the test code
buftype = vardef.base_type buftype = vardef.base_type
self.assert_(isinstance(buftype, CBufferAccessTypeNode)) self.assert_(isinstance(buftype, TemplatedTypeNode))
self.assert_(isinstance(buftype.base_type_node, CSimpleBaseTypeNode)) self.assert_(isinstance(buftype.base_type_node, CSimpleBaseTypeNode))
self.assertEqual(u"object", buftype.base_type_node.name) self.assertEqual(u"object", buftype.base_type_node.name)
return buftype return buftype
......
...@@ -100,7 +100,8 @@ class TreeVisitor(BasicVisitor): ...@@ -100,7 +100,8 @@ class TreeVisitor(BasicVisitor):
def dump_node(self, node, indent=0): def dump_node(self, node, indent=0):
ignored = list(node.child_attrs) + [u'child_attrs', u'pos', ignored = list(node.child_attrs) + [u'child_attrs', u'pos',
u'gil_message', u'subexprs'] u'gil_message', u'cpp_message',
u'subexprs']
values = [] values = []
pos = node.pos pos = node.pos
if pos: if pos:
......
cdef extern from "<vector>" 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 "<deque>" 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&)
...@@ -13,10 +13,11 @@ except: ...@@ -13,10 +13,11 @@ except:
ext_modules=[ ext_modules=[
Extension("primes", ["primes.pyx"]), Extension("primes", ["primes.pyx"]),
Extension("spam", ["spam.pyx"]), Extension("spam", ["spam.pyx"]),
Extension("square", ["square.pyx"], language="c++"),
] ]
for file in glob.glob("*.pyx"): for file in glob.glob("*.pyx"):
if file != "numeric_demo.pyx": if file != "numeric_demo.pyx" and file != "square.pyx":
ext_modules.append(Extension(file[:-4], [file], include_dirs = numpy_include_dirs)) ext_modules.append(Extension(file[:-4], [file], include_dirs = numpy_include_dirs))
setup( setup(
......
...@@ -649,7 +649,7 @@ class FileListExcluder: ...@@ -649,7 +649,7 @@ class FileListExcluder:
self.excludes[line.split()[0]] = True self.excludes[line.split()[0]] = True
def __call__(self, testname): def __call__(self, testname):
return testname.split('.')[-1] in self.excludes return testname in self.excludes or testname.split('.')[-1] in self.excludes
if __name__ == '__main__': if __name__ == '__main__':
from optparse import OptionParser from optparse import OptionParser
......
...@@ -8,3 +8,5 @@ unsignedbehaviour_T184 ...@@ -8,3 +8,5 @@ unsignedbehaviour_T184
missing_baseclass_in_predecl_T262 missing_baseclass_in_predecl_T262
cfunc_call_tuple_args_T408 cfunc_call_tuple_args_T408
cascaded_list_unpacking_T467 cascaded_list_unpacking_T467
compile.cpp_operators
cpp_nested_templates
cdef extern from "operators.h":
cdef cppclass Operators:
Operators(int)
Operators operator+(Operators)
Operators __add__(Operators, Operators)
Operators __sub__(Operators, Operators)
Operators __mul__(Operators, Operators)
Operators __div__(Operators, Operators)
bool __lt__(Operators, Operators)
bool __le__(Operators, Operators)
bool __eq__(Operators, Operators)
bool __ne__(Operators, Operators)
bool __gt__(Operators, Operators)
bool __ge__(Operators, Operators)
Operators __rshift__(Operators, int)
Operators __lshift__(Operators, int)
Operators __mod__(Operators, int)
cdef int v = 10
cdef Operators a
cdef Operators b
cdef Operators c
c = a + b
c = a - b
c = a * b
c = a / b
c = a << 2
c = a >> 1
c = b % 2
a < b
a <= b
a == b
a != b
a > b
a >= b
cdef extern from "templates.h":
cdef cppclass TemplateTest1[T]:
TemplateTest1()
T value
int t
T getValue()
cdef cppclass TemplateTest2[T, U]:
TemplateTest2()
T value1
U value2
T getValue1()
U getValue2()
cdef TemplateTest1[int] a
cdef TemplateTest1[int]* b = new TemplateTest1[int]()
cdef int c = a.getValue()
c = b.getValue()
cdef TemplateTest2[int, char] d
cdef TemplateTest2[int, char]* e = new TemplateTest2[int, char]()
c = d.getValue1()
c = e.getValue2()
cdef char f = d.getValue2()
f = e.getValue2()
del b, e
#ifndef _OPERATORS_H_
#define _OPERATORS_H_
class Operators
{
public:
int value;
Operators() { }
Operators(int value) { this->value = value; }
virtual ~Operators() { }
Operators operator+(Operators f) { return Operators(this->value + f.value); }
Operators operator-(Operators f) { return Operators(this->value - f.value); }
Operators operator*(Operators f) { return Operators(this->value * f.value); }
Operators operator/(Operators f) { return Operators(this->value / f.value); }
bool operator<(Operators f) { return this->value < f.value; }
bool operator<=(Operators f) { return this->value <= f.value; }
bool operator==(Operators f) { return this->value == f.value; }
bool operator!=(Operators f) { return this->value != f.value; }
bool operator>(Operators f) { return this->value > f.value; }
bool operator>=(Operators f) { return this->value >= f.value; }
Operators operator>>(int v) { return Operators(this->value >> v); }
Operators operator<<(int v) { return Operators(this->value << v); }
Operators operator%(int v) { return Operators(this->value % v); }
};
#endif
#ifndef _TEMPLATES_H_
#define _TEMPLATES_H_
template<class T>
class TemplateTest1
{
public:
T value;
int t;
TemplateTest1() { }
T getValue() { return value; }
};
template<class T, class U>
class TemplateTest2
{
public:
T value1;
U value2;
TemplateTest2() { }
T getValue1() { return value1; }
U getValue2() { return value2; }
};
#endif
...@@ -12,8 +12,8 @@ def f(): ...@@ -12,8 +12,8 @@ def f():
cdef object[int, 2, well] buf6 cdef object[int, 2, well] buf6
_ERRORS = u""" _ERRORS = u"""
1:11: Buffer types only allowed as function local variables 1:17: Buffer types only allowed as function local variables
3:15: Buffer types only allowed as function local variables 3:21: Buffer types only allowed as function local variables
6:27: "fakeoption" is not a buffer option 6:27: "fakeoption" is not a buffer option
""" """
#TODO: #TODO:
......
...@@ -12,7 +12,7 @@ def f(a): ...@@ -12,7 +12,7 @@ def f(a):
del s.m # error: deletion of non-Python object del s.m # error: deletion of non-Python object
_ERRORS = u""" _ERRORS = u"""
8:6: Cannot assign to or delete this 8:6: Cannot assign to or delete this
9:45: Deletion of non-Python object 9:45: Deletion of non-Python, non-C++ object
11:6: Deletion of non-Python object 11:6: Deletion of non-Python, non-C++ object
12:6: Deletion of non-Python object 12:6: Deletion of non-Python, non-C++ object
""" """
__doc__ = u"""
>>> test_new_del()
(2, 2)
>>> test_rect_area(3, 4)
12.0
>>> test_square_area(15)
(225.0, 225.0)
"""
cdef extern from "shapes.h" namespace shapes:
cdef cppclass Shape:
float area()
cdef cppclass Circle(Shape):
int radius
Circle(int)
cdef cppclass Rectangle(Shape):
int width
int height
Rectangle(int, int)
cdef cppclass Square(Rectangle):
int side
Square(int)
int constructor_count, destructor_count
def test_new_del():
cdef Rectangle *rect = new Rectangle(10, 20)
cdef Circle *circ = new Circle(15)
del rect, circ
return constructor_count, destructor_count
def test_rect_area(w, h):
cdef Rectangle *rect = new Rectangle(w, h)
try:
return rect.area()
finally:
del rect
def test_square_area(w):
cdef Square *sqr = new Square(w)
cdef Rectangle *rect = sqr
try:
return rect.area(), sqr.area()
finally:
del sqr
cdef double get_area(Rectangle s):
return s.area()
def test_value_call(int w):
"""
>>> test_value_call(5)
(25.0, 25.0)
"""
cdef Square *sqr = new Square(w)
cdef Rectangle *rect = sqr
try:
return get_area(sqr[0]), get_area(rect[0])
finally:
del sqr
from cython import dereference as deref
cdef extern from "cpp_templates_helper.h":
cdef cppclass Wrap[T]:
Wrap(T)
void set(T)
T get()
bint operator==(Wrap[T])
cdef cppclass Pair[T1,T2]:
Pair(T1,T2)
T1 first()
T2 second()
bint operator==(Pair[T1,T2])
bint operator!=(Pair[T1,T2])
def test_wrap_pair(int i, double x):
"""
>>> test_wrap_pair(1, 1.5)
(1, 1.5, True, False)
>>> test_wrap_pair(2, 2.25)
(2, 2.25, True, False)
"""
cdef Pair[int, double] *pair
cdef Wrap[Pair[int, double]] *wrap
try:
pair = new Pair[int, double](i, x)
warp = new Wrap[Pair[int, double]](deref(pair))
return wrap.get().first(), wrap.get().second(), deref(wrap) == deref(wrap)
finally:
del pair, wrap
cimport cython.operator
from cython.operator cimport dereference as deref
cdef extern from "cpp_operators_helper.h":
cdef cppclass TestOps:
char* operator+()
char* operator-()
char* operator*()
char* operator~()
char* operator++()
char* operator--()
char* operator++(int)
char* operator--(int)
char* operator+(int)
char* operator-(int)
char* operator*(int)
char* operator/(int)
char* operator%(int)
char* operator|(int)
char* operator&(int)
char* operator^(int)
char* operator<<(int)
char* operator>>(int)
char* operator==(int)
char* operator!=(int)
char* operator>=(int)
char* operator<=(int)
char* operator>(int)
char* operator<(int)
char* operator[](int)
char* operator()(int)
def test_unops():
"""
>>> test_unops()
unary +
unary -
unary ~
unary *
"""
cdef TestOps* t = new TestOps()
print +t[0]
print -t[0]
print ~t[0]
print deref(t[0])
del t
def test_incdec():
"""
>>> test_incdec()
unary ++
unary --
post ++
post --
"""
cdef TestOps* t = new TestOps()
print cython.operator.preincrement(t[0])
print cython.operator.predecrement(t[0])
print cython.operator.postincrement(t[0])
print cython.operator.postdecrement(t[0])
del t
def test_binop():
"""
>>> test_binop()
binary +
binary -
binary *
binary /
binary %
binary &
binary |
binary ^
binary <<
binary >>
"""
cdef TestOps* t = new TestOps()
print t[0] + 1
print t[0] - 1
print t[0] * 1
print t[0] / 1
print t[0] % 1
print t[0] & 1
print t[0] | 1
print t[0] ^ 1
print t[0] << 1
print t[0] >> 1
del t
def test_cmp():
"""
>>> test_cmp()
binary ==
binary !=
binary >=
binary >
binary <=
binary <
"""
cdef TestOps* t = new TestOps()
print t[0] == 1
print t[0] != 1
print t[0] >= 1
print t[0] > 1
print t[0] <= 1
print t[0] < 1
del t
def test_index_call():
"""
>>> test_index_call()
binary []
binary ()
"""
cdef TestOps* t = new TestOps()
print t[0][100]
print t[0](100)
del t
#define UN_OP(op) const char* operator op () { return "unary "#op; }
#define POST_UN_OP(op) const char* operator op (int x) { return "post "#op; }
#define BIN_OP(op) const char* operator op (int x) { return "binary "#op; }
class TestOps {
public:
UN_OP(-);
UN_OP(+);
UN_OP(*);
UN_OP(~);
UN_OP(!);
UN_OP(&);
UN_OP(++);
UN_OP(--);
POST_UN_OP(++);
POST_UN_OP(--);
BIN_OP(+);
BIN_OP(-);
BIN_OP(*);
BIN_OP(/);
BIN_OP(%);
BIN_OP(<<);
BIN_OP(>>);
BIN_OP(|);
BIN_OP(&);
BIN_OP(^);
BIN_OP(==);
BIN_OP(!=);
BIN_OP(<=);
BIN_OP(<);
BIN_OP(>=);
BIN_OP(>);
BIN_OP([]);
BIN_OP(());
};
__doc__ = u"""
>>> test_vector([1,10,100])
1
10
100
"""
cdef extern from "vector" namespace std:
cdef cppclass iterator[T]:
pass
cdef cppclass vector[T]:
#constructors
__init__()
T at(int)
void push_back(T t)
void assign(int, T)
void clear()
iterator end()
iterator begin()
int size()
def test_vector(L):
cdef vector[int] *V = new vector[int]()
for a in L:
V.push_back(a)
cdef int i
for i in range(len(L)):
print V.at(i)
del V
cdef extern from "<vector>" namespace std:
cdef cppclass vector[T]:
void push_back(T)
size_t size()
T operator[](size_t)
def simple_test(double x):
"""
>>> simple_test(55)
3
"""
cdef vector[double] *v
try:
v = new vector[double]()
v.push_back(1.0)
v.push_back(x)
from math import pi
v.push_back(pi)
return v.size()
finally:
del v
def list_test(L):
"""
>>> list_test([1,2,4,8])
(4, 4)
>>> list_test([])
(0, 0)
>>> list_test([-1] * 1000)
(1000, 1000)
"""
cdef vector[int] *v
try:
v = new vector[int]()
for a in L:
v.push_back(a)
return len(L), v.size()
finally:
del v
def index_test(L):
"""
>>> index_test([1,2,4,8])
(1.0, 8.0)
>>> index_test([1.25])
(1.25, 1.25)
"""
cdef vector[double] *v
try:
v = new vector[double]()
for a in L:
v.push_back(a)
return v[0][0], v[0][len(L)-1]
finally:
del v
from cython.operator import dereference as deref
cdef extern from "cpp_templates_helper.h":
cdef cppclass Wrap[T]:
Wrap(T)
void set(T)
T get()
bint operator==(Wrap[T])
cdef cppclass Pair[T1,T2]:
Pair(T1,T2)
T1 first()
T2 second()
bint operator==(Pair[T1,T2])
bint operator!=(Pair[T1,T2])
def test_int(int x, int y):
"""
>>> test_int(3, 4)
(3, 4, False)
>>> test_int(100, 100)
(100, 100, True)
"""
cdef Wrap[int] *a, *b
try:
a = new Wrap[int](x)
b = new Wrap[int](0)
b.set(y)
return a.get(), b.get(), a[0] == b[0]
finally:
del a, b
def test_double(double x, double y):
"""
>>> test_double(3, 3.5)
(3.0, 3.5, False)
>>> test_double(100, 100)
(100.0, 100.0, True)
"""
cdef Wrap[double] *a, *b
try:
a = new Wrap[double](x)
b = new Wrap[double](-1)
b.set(y)
return a.get(), b.get(), deref(a) == deref(b)
finally:
del a, b
def test_pair(int i, double x):
"""
>>> test_pair(1, 1.5)
(1, 1.5, True, False)
>>> test_pair(2, 2.25)
(2, 2.25, True, False)
"""
cdef Pair[int, double] *pair
try:
pair = new Pair[int, double](i, x)
return pair.first(), pair.second(), deref(pair) == deref(pair), deref(pair) != deref(pair)
finally:
del pair
template <class T>
class Wrap {
T value;
public:
Wrap(T v) { value = v; }
void set(T v) { value = v; }
T get(void) { return value; }
bool operator==(Wrap<T> other) { return value == other.value; }
};
template <class T1, class T2>
class Pair {
T1 _first;
T2 _second;
public:
Pair(T1 u, T2 v) { _first = u; _second = v; }
T1 first(void) { return _first; }
T2 second(void) { return _second; }
bool operator==(Pair<T1,T2> other) { return _first == other._first && _second == other._second; }
bool operator!=(Pair<T1,T2> other) { return _first != other._first || _second != other._second; }
};
cdef extern from *:
int new(int new)
def new(x):
"""
>>> new(3)
3
"""
cdef int new = x
return new
def x(new):
"""
>>> x(10)
110
>>> x(1)
1
"""
if new*new != new:
return new + new**2
return new
class A:
def new(self, n):
"""
>>> a = A()
>>> a.new(3)
6
>>> a.new(5)
120
"""
if n <= 1:
return 1
else:
return n * self.new(n-1)
#ifndef SHAPES_H
#define SHAPES_H
namespace shapes {
int constructor_count = 0;
int destructor_count = 0;
class Shape
{
public:
virtual float area() = 0;
Shape() { constructor_count++; }
virtual ~Shape() { destructor_count++; }
};
class Rectangle : public Shape
{
public:
Rectangle(int width, int height)
{
this->width = width;
this->height = height;
}
float area() { return width * height; }
int width;
int height;
};
class Square : public Rectangle
{
public:
Square(int side) : Rectangle(side, side) { this->side = side; }
int side;
};
class Circle : public Shape {
public:
Circle(int radius) { this->radius = radius; }
float area() { return 3.1415926535897931f * radius; }
int radius;
};
}
#endif
cimport cython
def test_deref(int x):
"""
>>> test_deref(3)
3
>>> test_deref(5)
5
"""
cdef int* x_ptr = &x
return cython.dereference(x_ptr)
def increment_decrement(int x):
"""
>>> increment_decrement(10)
11 11 12
11 11 10
10
"""
print cython.preincrement(x), cython.postincrement(x), x
print cython.predecrement(x), cython.postdecrement(x), x
return x
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment