From e6185bed79260f2ecd9cec0c02083f1ee72b75ea Mon Sep 17 00:00:00 2001 From: Danilo Freitas Date: Tue, 11 Aug 2009 12:59:51 -0300 Subject: [PATCH] Templates --- Cython/Compiler/ExprNodes.py | 1 + Cython/Compiler/Nodes.py | 30 +++++++++++++++++---- Cython/Compiler/Parsing.py | 51 ++++++++++++++++++++++++----------- Cython/Compiler/PyrexTypes.py | 30 ++++++++++++++++++--- Cython/Compiler/Symtab.py | 8 ++---- 5 files changed, 91 insertions(+), 29 deletions(-) diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index ab9b601c..6691c7f6 100755 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -1123,6 +1123,7 @@ class ImagNode(AtomicNewTempExprNode): class NewExprNode(AtomicExprNode): def analyse_types(self, env): + print self.cppclass entry = env.lookup(self.cppclass) if entry is None or not entry.is_cpp_class: error(self.pos, "new operator can only be applied to a C++ class") diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 51031495..f0c43f01 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -721,11 +721,13 @@ class CSimpleBaseTypeNode(CBaseTypeNode): else: type = py_object_type self.arg_name = self.name - elif self.templates: - if not self.name in self.templates: - error(self.pos, "'%s' is not a type identifier" % 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.TemplatedType(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") @@ -736,6 +738,24 @@ class CSimpleBaseTypeNode(CBaseTypeNode): else: return PyrexTypes.error_type +class TemplatedTypeNode(CBaseTypeNode): + # name + # base_type_node CSimpleBaseTypeNode + # templates [CSimpleBaseTypeNode] + + child_attrs = ["base_type_node", "templates"] + + def analyse(self, env, could_be_name = False): + entry = env.lookup(self.base_type_node.name) + base_types = entry.type.templates + if not base_types: + error(self.pos, "%s type is not a template" % entry.type) + if len(base_types) != len(self.templates): + error(self.pos, "%s templated type receives %d arguments, got %d" % + (entry.type, len(base_types), len(self.templates))) + print entry.type + return entry.type + class CBufferAccessTypeNode(CBaseTypeNode): # After parsing: # positional_args [ExprNode] List of positional arguments @@ -935,7 +955,7 @@ class CppClassNode(CStructOrUnionDefNode): base_class_types.append(base_class_entry.type) self.entry = env.declare_cpp_class( self.name, "cppclass", scope, 0, self.pos, - self.cname, base_class_types, visibility = self.visibility) + self.cname, base_class_types, visibility = self.visibility, templates = self.templates) self.entry.is_cpp_class = 1 if self.attributes is not None: if self.in_pxd and not env.in_cinclude: diff --git a/Cython/Compiler/Parsing.py b/Cython/Compiler/Parsing.py index bf16c952..0b1d3279 100644 --- a/Cython/Compiler/Parsing.py +++ b/Cython/Compiler/Parsing.py @@ -1787,29 +1787,50 @@ def p_c_simple_base_type(s, self_flag, nonempty, templates = None): # (This means that buffers cannot occur where there can be empty declarators, # which is an ok restriction to make.) if nonempty and s.sy == '[': - return p_buffer_access(s, type_node) + return p_buffer_or_template(s, type_node) else: return type_node -def p_buffer_access(s, base_type_node): +def p_buffer_or_template(s, base_type_node): # s.sy == '[' pos = s.position() s.next() - positional_args, keyword_args = ( - p_positional_and_keyword_args(s, (']',), (0,), ('dtype',)) - ) - s.expect(']') + if s.systring == 'int' or s.systring == 'long': + positional_args, keyword_args = ( + p_positional_and_keyword_args(s, (']',), (0,), ('dtype',)) + ) + if keyword_args: + error(pos, "Keyword arguments not allowed for template types") + 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, base_type_node = base_type_node, + templates = positional_args) + else: + positional_args, keyword_args = ( + p_positional_and_keyword_args(s, (']',), (0,), ('dtype',)) + ) + if positional_args: + if positional_args[0] != 'int' or positional_args != 'long': + if keyword_args: + error(pos, "Keyword arguments not allowed for template types") + s.expect(']') - result = Nodes.CBufferAccessTypeNode(pos, - positional_args = positional_args, - keyword_args = keyword_dict, - base_type_node = base_type_node) + result = Nodes.TemplatedTypeNode(pos, base_type_node = base_type_node, + templates = positional_args) + else: + 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.CBufferAccessTypeNode(pos, + positional_args = positional_args, + keyword_args = keyword_dict, + base_type_node = base_type_node) + return result diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py index 5c1c136f..103e7524 100755 --- a/Cython/Compiler/PyrexTypes.py +++ b/Cython/Compiler/PyrexTypes.py @@ -1015,13 +1015,15 @@ class CFuncType(CType): # 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): + 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 @@ -1032,6 +1034,7 @@ class CFuncType(CType): 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) @@ -1370,12 +1373,14 @@ class CppClassType(CType): # scope CppClassScope # typedef_flag boolean # packed boolean + # templates [string] or None is_cpp_class = 1 has_attributes = 1 base_classes = [] - def __init__(self, name, kind, scope, typedef_flag, cname, base_classes, packed=False): + def __init__(self, name, kind, scope, typedef_flag, cname, base_classes, packed=False, + templates = None): self.name = name self.cname = cname self.kind = kind @@ -1386,13 +1391,24 @@ class CppClassType(CType): self.packed = packed self.base_classes = base_classes self.operators = [] + self.templates = templates def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0): + templates = "" + if self.templates: + templates = "<" + for i in range(len(self.templates)-1): + templates += "class " + templates += self.templates[i] + templates += ',' + templates += "class " + templates += self.templates[-1] + templates += ">" if for_display or pyrex: name = self.name else: name = self.cname - return "%s %s" % (name, entity_code) + return "%s %s%s" % (name, entity_code, templates) def is_subclass(self, other_type): if self.same_as_resolved_type(other_type): @@ -1405,6 +1421,14 @@ class CppClassType(CType): def attributes_known(self): return self.scope is not None +class TemplatedType(CType): + + def __init__(self, name): + self.name = name + + def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0): + return "" + class CEnumType(CType): # name string # cname string or None diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index d3ecd3f6..f33ab037 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -473,10 +473,6 @@ class Scope(object): else: entry = self.add_cfunction(name, type, pos, cname, visibility, modifiers) entry.func_cname = cname - #try: - # print entry.name, entry.type, entry.overloaded_alternatives - #except: - # pass if in_pxd and visibility != 'extern': entry.defined_in_pxd = 1 if api: @@ -1116,7 +1112,7 @@ class ModuleScope(Scope): def declare_cpp_class(self, name, kind, scope, typedef_flag, pos, cname = None, base_classes = [], - visibility = 'extern', packed = False): + visibility = 'extern', packed = False, templates = None): if visibility != 'extern': error(pos, "C++ classes may only be extern") if cname is None: @@ -1124,7 +1120,7 @@ class ModuleScope(Scope): entry = self.lookup(name) if not entry: type = PyrexTypes.CppClassType( - name, kind, scope, typedef_flag, cname, base_classes, packed) + name, kind, scope, typedef_flag, cname, base_classes, packed, templates = templates) entry = self.declare_type(name, type, pos, cname, visibility = visibility, defining = scope is not None) else: -- 2.26.2