+
#
# Pyrex - Parse tree nodes
#
import TypeSlots
from PyrexTypes import py_object_type, error_type, CFuncType
from Symtab import ModuleScope, LocalScope, GeneratorLocalScope, \
- StructOrUnionScope, PyClassScope, CClassScope
+ 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_docstring
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
def analyse_expressions(self, env):
#print "StatListNode.analyse_expressions" ###
+ entry = env.entries.get("cpp_sum", None)
for stat in self.stats:
stat.analyse_expressions(env)
"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
pass
+ def analyse_as_type(self, env):
+ return self.analyse(env)
+
class CAnalysedBaseTypeNode(Node):
# type type
type = py_object_type
self.arg_name = self.name
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 not type.is_numeric or type.is_complex:
error(self.pos, "can only complexify c numeric types")
else:
return PyrexTypes.error_type
-class CBufferAccessTypeNode(CBaseTypeNode):
+class TemplatedTypeNode(CBaseTypeNode):
# After parsing:
# positional_args [ExprNode] List of positional arguments
# keyword_args DictNode Keyword arguments
# base_type_node CBaseTypeNode
# 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",
name = None
- def analyse(self, env, could_be_name = False):
- base_type = self.base_type_node.analyse(env)
+ 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
- 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(
- self.pos,
- env,
- self.positional_args,
- self.keyword_args,
- base_type.buffer_defaults)
+ 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() ])
+ 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)
+ self.type = PyrexTypes.BufferType(base_type, **options)
return self.type
class CComplexBaseTypeNode(CBaseTypeNode):
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):
# name string or None
# cname string or None
def analyse_expressions(self, env):
for arg in self.args:
arg.analyse_target_expression(env, None)
- if not arg.type.is_pyobject:
- error(arg.pos, "Deletion of non-Python object")
+ if arg.type.is_pyobject:
+ self.gil_check(env)
+ 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:
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):