X-Git-Url: http://git.tremily.us/?a=blobdiff_plain;f=Cython%2FCompiler%2FNodes.py;h=68dd042dc756810a87bc38c581a744a6d5e77edb;hb=73da9b353950aa68b4e059ca86ab58076af2103d;hp=e6b00487627784e71f92e67a22e311ad6272dfba;hpb=5109df243090ec49b3f6cdc5254feaacda464afd;p=cython.git diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index e6b00487..68dd042d 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -1,3 +1,4 @@ + # # Pyrex - Parse tree nodes # @@ -18,7 +19,7 @@ import PyrexTypes 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 @@ -143,6 +144,15 @@ class Node(object): 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 @@ -332,6 +342,7 @@ class StatListNode(Node): 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) @@ -447,7 +458,19 @@ class CPtrDeclaratorNode(CDeclaratorNode): "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 @@ -655,6 +678,9 @@ class CBaseTypeNode(Node): pass + def analyse_as_type(self, env): + return self.analyse(env) + class CAnalysedBaseTypeNode(Node): # type type @@ -714,7 +740,12 @@ class CSimpleBaseTypeNode(CBaseTypeNode): 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") @@ -725,14 +756,14 @@ class CSimpleBaseTypeNode(CBaseTypeNode): 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", @@ -742,24 +773,38 @@ class CBufferAccessTypeNode(CBaseTypeNode): 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): @@ -904,6 +949,46 @@ class CStructOrUnionDefNode(StatNode): 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 @@ -3387,8 +3472,14 @@ class DelStatNode(StatNode): 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): @@ -3402,6 +3493,9 @@ class DelStatNode(StatNode): 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):