diff options
author | Anton Samokhvalov <pg83@yandex.ru> | 2022-02-10 16:45:15 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:15 +0300 |
commit | 72cb13b4aff9bc9cf22e49251bc8fd143f82538f (patch) | |
tree | da2c34829458c7d4e74bdfbdf85dff449e9e7fb8 /contrib/tools/cython/Cython/Compiler/Symtab.py | |
parent | 778e51ba091dc39e7b7fcab2b9cf4dbedfb6f2b5 (diff) | |
download | ydb-72cb13b4aff9bc9cf22e49251bc8fd143f82538f.tar.gz |
Restoring authorship annotation for Anton Samokhvalov <pg83@yandex.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/tools/cython/Cython/Compiler/Symtab.py')
-rw-r--r-- | contrib/tools/cython/Cython/Compiler/Symtab.py | 4148 |
1 files changed, 2074 insertions, 2074 deletions
diff --git a/contrib/tools/cython/Cython/Compiler/Symtab.py b/contrib/tools/cython/Cython/Compiler/Symtab.py index 7361a55aea..037b5d2d9a 100644 --- a/contrib/tools/cython/Cython/Compiler/Symtab.py +++ b/contrib/tools/cython/Cython/Compiler/Symtab.py @@ -1,11 +1,11 @@ -# -# Symbol Table -# - -from __future__ import absolute_import - +# +# Symbol Table +# + +from __future__ import absolute_import + import re -import copy +import copy import operator try: @@ -13,440 +13,440 @@ try: except ImportError: # Py3 import builtins -from .Errors import warning, error, InternalError -from .StringEncoding import EncodedString -from . import Options, Naming -from . import PyrexTypes -from .PyrexTypes import py_object_type, unspecified_type +from .Errors import warning, error, InternalError +from .StringEncoding import EncodedString +from . import Options, Naming +from . import PyrexTypes +from .PyrexTypes import py_object_type, unspecified_type from .TypeSlots import ( pyfunction_signature, pymethod_signature, richcmp_special_methods, get_special_method_signature, get_property_accessor_signature) from . import Future -from . import Code - -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. +from . import Code + +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 in ('__weakref__', '__dict__'))) or cname in iso_c99_keywords): - cname = Naming.pyrex_prefix + cname - return cname - - -class BufferAux(object): - writable_needed = False - - def __init__(self, buflocal_nd_var, rcbuf_var): - self.buflocal_nd_var = buflocal_nd_var - self.rcbuf_var = rcbuf_var - - def __repr__(self): - return "<BufferAux %r>" % 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 + cname = Naming.pyrex_prefix + cname + return cname + + +class BufferAux(object): + writable_needed = False + + def __init__(self, buflocal_nd_var, rcbuf_var): + self.buflocal_nd_var = buflocal_nd_var + self.rcbuf_var = rcbuf_var + + def __repr__(self): + return "<BufferAux %r>" % 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 # annotation ExprNode PEP 484/526 annotation - # 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_pyclass_attr boolean Is a name in a Python class namespace - # 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_builtin_cmethod boolean Is a C method of a builtin type (implies is_cmethod) - # is_unbound_cmethod boolean Is an unbound C method of an extension type - # is_final_cmethod boolean Is non-overridable C method - # is_inline_cmethod boolean Is inlined C method - # is_anonymous boolean Is a anonymous pyfunction entry - # 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 + # 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_pyclass_attr boolean Is a name in a Python class namespace + # 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_builtin_cmethod boolean Is a C method of a builtin type (implies is_cmethod) + # is_unbound_cmethod boolean Is an unbound C method of an extension type + # is_final_cmethod boolean Is non-overridable C method + # is_inline_cmethod boolean Is inlined C method + # is_anonymous boolean Is a anonymous pyfunction entry + # 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 # in_subscope boolean Belongs to a generator expression 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 - # 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. + # 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 + # 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 necessary. - # might_overflow boolean In an arithmetic expression that could cause - # overflow (used for type inference). - # utility_code_definition For some Cython builtins, the utility code - # which contains the definition of the entry. - # Currently only supported for CythonScope entries. - # error_on_uninitialized Have Control Flow issue an error when this entry is - # used uninitialized - # cf_used boolean Entry is used - # is_fused_specialized boolean Whether this entry of a cdef or def function - # is a specialization - - # TODO: utility_code and utility_code_definition serves the same purpose... - - inline_func_in_pxd = False - borrowed = 0 - init = "" + # might_overflow boolean In an arithmetic expression that could cause + # overflow (used for type inference). + # utility_code_definition For some Cython builtins, the utility code + # which contains the definition of the entry. + # Currently only supported for CythonScope entries. + # error_on_uninitialized Have Control Flow issue an error when this entry is + # used uninitialized + # cf_used boolean Entry is used + # is_fused_specialized boolean Whether this entry of a cdef or def function + # is a specialization + + # TODO: utility_code and utility_code_definition serves the same purpose... + + inline_func_in_pxd = False + borrowed = 0 + init = "" annotation = None - visibility = 'private' - is_builtin = 0 - is_cglobal = 0 - is_pyglobal = 0 - is_member = 0 - is_pyclass_attr = 0 - is_variable = 0 - is_cfunction = 0 - is_cmethod = 0 - is_builtin_cmethod = False - is_unbound_cmethod = 0 - is_final_cmethod = 0 - is_inline_cmethod = 0 - is_anonymous = 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 + visibility = 'private' + is_builtin = 0 + is_cglobal = 0 + is_pyglobal = 0 + is_member = 0 + is_pyclass_attr = 0 + is_variable = 0 + is_cfunction = 0 + is_cmethod = 0 + is_builtin_cmethod = False + is_unbound_cmethod = 0 + is_final_cmethod = 0 + is_inline_cmethod = 0 + is_anonymous = 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 in_subscope = 0 - is_declared_generic = 0 - is_readonly = 0 - pyfunc_cname = None - func_cname = None - func_modifiers = [] - final_func_cname = None - doc = None - 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 - fused_cfunction = None - is_fused_specialized = False - utility_code_definition = None - needs_property = False - in_with_gil_block = 0 - from_cython_utility_code = None - error_on_uninitialized = False - cf_used = True - outer_entry = None - - 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.cf_assignments = [] - self.cf_references = [] - self.inner_entries = [] - self.defining_entry = self - - def __repr__(self): - return "%s(<%x>, name=%s, type=%s)" % (type(self).__name__, id(self), self.name, self.type) - + is_declared_generic = 0 + is_readonly = 0 + pyfunc_cname = None + func_cname = None + func_modifiers = [] + final_func_cname = None + doc = None + 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 + fused_cfunction = None + is_fused_specialized = False + utility_code_definition = None + needs_property = False + in_with_gil_block = 0 + from_cython_utility_code = None + error_on_uninitialized = False + cf_used = True + outer_entry = None + + 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.cf_assignments = [] + self.cf_references = [] + self.inner_entries = [] + self.defining_entry = self + + def __repr__(self): + return "%s(<%x>, name=%s, type=%s)" % (type(self).__name__, id(self), self.name, self.type) + def already_declared_here(self): error(self.pos, "Previous declaration is here") - def redeclared(self, pos): - error(pos, "'%s' does not match previous declaration" % self.name) + def redeclared(self, pos): + error(pos, "'%s' does not match previous declaration" % self.name) self.already_declared_here() - - def all_alternatives(self): - return [self] + self.overloaded_alternatives - - def all_entries(self): - return [self] + self.inner_entries - + + def all_alternatives(self): + return [self] + self.overloaded_alternatives + + def all_entries(self): + return [self] + self.inner_entries + def __lt__(left, right): if isinstance(left, Entry) and isinstance(right, Entry): return (left.name, left.cname) < (right.name, right.cname) else: return NotImplemented - - -class InnerEntry(Entry): - """ - An entry in a closure scope that represents the real outer Entry. - """ - from_closure = True - - def __init__(self, outer_entry, scope): - Entry.__init__(self, outer_entry.name, - outer_entry.cname, - outer_entry.type, - outer_entry.pos) - self.outer_entry = outer_entry - self.scope = scope - - # share state with (outermost) defining entry - outermost_entry = outer_entry - while outermost_entry.outer_entry: - outermost_entry = outermost_entry.outer_entry - self.defining_entry = outermost_entry - self.inner_entries = outermost_entry.inner_entries - self.cf_assignments = outermost_entry.cf_assignments - self.cf_references = outermost_entry.cf_references - self.overloaded_alternatives = outermost_entry.overloaded_alternatives - self.inner_entries.append(self) - - def __getattr__(self, name): - if name.startswith('__'): - # we wouldn't have been called if it was there - raise AttributeError(name) - return getattr(self.defining_entry, name) - - def all_entries(self): - return self.defining_entry.all_entries() - - -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 - # return_type PyrexType or None Return type of function owning scope - # is_builtin_scope boolean Is the builtin scope of Python/Cython - # 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 a closure scope - # is_passthrough boolean Outer scope is passed directly - # 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" - # Python strings in this scope - # 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_builtin_scope = 0 - is_py_class_scope = 0 - is_c_class_scope = 0 - is_closure_scope = 0 + + +class InnerEntry(Entry): + """ + An entry in a closure scope that represents the real outer Entry. + """ + from_closure = True + + def __init__(self, outer_entry, scope): + Entry.__init__(self, outer_entry.name, + outer_entry.cname, + outer_entry.type, + outer_entry.pos) + self.outer_entry = outer_entry + self.scope = scope + + # share state with (outermost) defining entry + outermost_entry = outer_entry + while outermost_entry.outer_entry: + outermost_entry = outermost_entry.outer_entry + self.defining_entry = outermost_entry + self.inner_entries = outermost_entry.inner_entries + self.cf_assignments = outermost_entry.cf_assignments + self.cf_references = outermost_entry.cf_references + self.overloaded_alternatives = outermost_entry.overloaded_alternatives + self.inner_entries.append(self) + + def __getattr__(self, name): + if name.startswith('__'): + # we wouldn't have been called if it was there + raise AttributeError(name) + return getattr(self.defining_entry, name) + + def all_entries(self): + return self.defining_entry.all_entries() + + +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 + # return_type PyrexType or None Return type of function owning scope + # is_builtin_scope boolean Is the builtin scope of Python/Cython + # 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 a closure scope + # is_passthrough boolean Outer scope is passed directly + # 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" + # Python strings in this scope + # 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_builtin_scope = 0 + is_py_class_scope = 0 + is_c_class_scope = 0 + is_closure_scope = 0 is_genexpr_scope = 0 - is_passthrough = 0 - is_cpp_class_scope = 0 - is_property_scope = 0 - is_module_scope = 0 - is_internal = 0 - scope_prefix = "" - in_cinclude = 0 - nogil = 0 - fused_to_specific = None + is_passthrough = 0 + is_cpp_class_scope = 0 + is_property_scope = 0 + is_module_scope = 0 + is_internal = 0 + scope_prefix = "" + in_cinclude = 0 + nogil = 0 + fused_to_specific = None return_type = None - - 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 + + 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.replace('.', '_dot_')) - 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 = EncodedString(name) - self.scope_prefix = mangled_name - self.entries = {} + 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 = EncodedString(name) + self.scope_prefix = mangled_name + self.entries = {} self.subscopes = set() - 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.buffer_entries = [] - self.lambda_defs = [] - self.id_counters = {} - - def __deepcopy__(self, memo): - return self - - def merge_in(self, other, merge_unused=True, whitelist=None): - # Use with care... - 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.buffer_entries = [] + self.lambda_defs = [] + self.id_counters = {} + + def __deepcopy__(self, memo): + return self + + def merge_in(self, other, merge_unused=True, whitelist=None): + # Use with care... + entries = [] for name, entry in other.entries.items(): - if not whitelist or name in whitelist: - if entry.used or merge_unused: - entries.append((name, entry)) - - self.entries.update(entries) - - for attr in ('const_entries', - 'type_entries', - 'sue_entries', - 'arg_entries', - 'var_entries', - 'pyfunc_entries', - 'cfunc_entries', - 'c_class_entries'): - self_entries = getattr(self, attr) - names = set(e.name for e in self_entries) - for entry in getattr(other, attr): - if (entry.used or merge_unused) and entry.name not in names: - self_entries.append(entry) - - 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 mangle_class_private_name(self, name): - if self.parent_scope: - return self.parent_scope.mangle_class_private_name(name) - return name - - def next_id(self, name=None): - # Return a cname fragment that is unique for this module - counters = self.global_scope().id_counters - try: - count = counters[name] + 1 - except KeyError: - count = 0 - counters[name] = count - if name: - if not count: - # unique names don't need a suffix, reoccurrences will get one - return 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() - + if not whitelist or name in whitelist: + if entry.used or merge_unused: + entries.append((name, entry)) + + self.entries.update(entries) + + for attr in ('const_entries', + 'type_entries', + 'sue_entries', + 'arg_entries', + 'var_entries', + 'pyfunc_entries', + 'cfunc_entries', + 'c_class_entries'): + self_entries = getattr(self, attr) + names = set(e.name for e in self_entries) + for entry in getattr(other, attr): + if (entry.used or merge_unused) and entry.name not in names: + self_entries.append(entry) + + 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 mangle_class_private_name(self, name): + if self.parent_scope: + return self.parent_scope.mangle_class_private_name(name) + return name + + def next_id(self, name=None): + # Return a cname fragment that is unique for this module + counters = self.global_scope().id_counters + try: + count = counters[name] + 1 + except KeyError: + count = 0 + counters[name] = count + if name: + if not count: + # unique names don't need a suffix, reoccurrences will get one + return 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 iter_local_scopes(self): yield self if self.subscopes: for scope in sorted(self.subscopes, key=operator.attrgetter('scope_prefix')): yield scope - def declare(self, name, cname, type, pos, visibility, shadow = 0, is_type = 0, create_wrapper = 0): - # 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): # and not is_type: - error(pos, 'Buffer types only allowed as function local variables') - 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 and not shadow: + def declare(self, name, cname, type, pos, visibility, shadow = 0, is_type = 0, create_wrapper = 0): + # 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): # and not is_type: + error(pos, 'Buffer types only allowed as function local variables') + 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 and not shadow: old_entry = entries[name] # Reject redeclared C++ functions only if they have the same type signature. @@ -471,296 +471,296 @@ class Scope(object): # Silenced outside of "cdef extern" blocks, until we have a safe way to # prevent pxd-defined cpdef functions from ending up here. warning(pos, "'%s' redeclared " % name, 1 if self.in_cinclude else 0) - elif visibility != 'ignore': - error(pos, "'%s' redeclared " % name) + elif visibility != 'ignore': + error(pos, "'%s' redeclared " % name) entries[name].already_declared_here() - entry = Entry(name, cname, type, pos = pos) - entry.in_cinclude = self.in_cinclude - entry.create_wrapper = create_wrapper - 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 - if not shadow: - entries[name] = entry - - if type.is_memoryviewslice: - from . import MemoryView - entry.init = MemoryView.memslice_entry_init - - entry.scope = self - entry.visibility = visibility - return entry - - def qualify_name(self, name): - return EncodedString("%s.%s" % (self.qualified_name, name)) - - def declare_const(self, name, type, value, pos, cname = None, visibility = 'private', api = 0, create_wrapper = 0): - # Add an entry for a named constant. - if not cname: - if self.in_cinclude or (visibility == 'public' or api): - cname = name - else: - cname = self.mangle(Naming.enum_prefix, name) - entry = self.declare(name, cname, type, pos, visibility, create_wrapper = create_wrapper) - entry.is_const = 1 - entry.value_node = value - return entry - - def declare_type(self, name, type, pos, - cname = None, visibility = 'private', api = 0, defining = 1, - shadow = 0, template = 0): - # Add an entry for a type definition. - if not cname: - cname = name - entry = self.declare(name, cname, type, pos, visibility, shadow, - is_type=True) - entry.is_type = 1 - entry.api = api - if defining: - self.type_entries.append(entry) - - if not template: - type.entry = 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', api = 0): - if not cname: + entry = Entry(name, cname, type, pos = pos) + entry.in_cinclude = self.in_cinclude + entry.create_wrapper = create_wrapper + 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 + if not shadow: + entries[name] = entry + + if type.is_memoryviewslice: + from . import MemoryView + entry.init = MemoryView.memslice_entry_init + + entry.scope = self + entry.visibility = visibility + return entry + + def qualify_name(self, name): + return EncodedString("%s.%s" % (self.qualified_name, name)) + + def declare_const(self, name, type, value, pos, cname = None, visibility = 'private', api = 0, create_wrapper = 0): + # Add an entry for a named constant. + if not cname: + if self.in_cinclude or (visibility == 'public' or api): + cname = name + else: + cname = self.mangle(Naming.enum_prefix, name) + entry = self.declare(name, cname, type, pos, visibility, create_wrapper = create_wrapper) + entry.is_const = 1 + entry.value_node = value + return entry + + def declare_type(self, name, type, pos, + cname = None, visibility = 'private', api = 0, defining = 1, + shadow = 0, template = 0): + # Add an entry for a type definition. + if not cname: + cname = name + entry = self.declare(name, cname, type, pos, visibility, shadow, + is_type=True) + entry.is_type = 1 + entry.api = api + if defining: + self.type_entries.append(entry) + + if not template: + type.entry = 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', api = 0): + if not cname: if self.in_cinclude or (visibility != 'private' or api): - cname = name - else: - cname = self.mangle(Naming.type_prefix, name) - try: + cname = name + else: + cname = self.mangle(Naming.type_prefix, name) + try: if self.is_cpp_class_scope: namespace = self.outer_scope.lookup(self.name).type else: namespace = None - type = PyrexTypes.create_typedef_type(name, base_type, cname, + type = PyrexTypes.create_typedef_type(name, base_type, cname, (visibility == 'extern'), namespace) except ValueError as e: - error(pos, e.args[0]) - type = PyrexTypes.error_type - entry = self.declare_type(name, type, pos, cname, - visibility = visibility, api = api) - type.qualified_name = entry.qualified_name - return entry - - def declare_struct_or_union(self, name, kind, scope, - typedef_flag, pos, cname = None, - visibility = 'private', api = 0, - packed = False): - # Add an entry for a struct or union definition. - if not cname: - if self.in_cinclude or (visibility == 'public' or api): - 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, api = api, - 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) + error(pos, e.args[0]) + type = PyrexTypes.error_type + entry = self.declare_type(name, type, pos, cname, + visibility = visibility, api = api) + type.qualified_name = entry.qualified_name + return entry + + def declare_struct_or_union(self, name, kind, scope, + typedef_flag, pos, cname = None, + visibility = 'private', api = 0, + packed = False): + # Add an entry for a struct or union definition. + if not cname: + if self.in_cinclude or (visibility == 'public' or api): + 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, api = api, + 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 self.is_cpp_class_scope: entry.type.namespace = self.outer_scope.lookup(self.name).type - return entry - - def declare_cpp_class(self, name, scope, - pos, cname = None, base_classes = (), - visibility = 'extern', templates = None): - if cname is None: - if self.in_cinclude or (visibility != 'private'): - cname = name - else: - cname = self.mangle(Naming.type_prefix, name) - base_classes = list(base_classes) - 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) - self.sue_entries.append(entry) - else: - if not (entry.is_type and entry.type.is_cpp_class): - error(pos, "'%s' redeclared " % name) + return entry + + def declare_cpp_class(self, name, scope, + pos, cname = None, base_classes = (), + visibility = 'extern', templates = None): + if cname is None: + if self.in_cinclude or (visibility != 'private'): + cname = name + else: + cname = self.mangle(Naming.type_prefix, name) + base_classes = list(base_classes) + 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) + self.sue_entries.append(entry) + else: + if not (entry.is_type and entry.type.is_cpp_class): + error(pos, "'%s' redeclared " % name) entry.already_declared_here() - return None - 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 base_classes: - if entry.type.base_classes and entry.type.base_classes != base_classes: - error(pos, "Base type does not match previous declaration") + return None + 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 base_classes: + if entry.type.base_classes and entry.type.base_classes != base_classes: + error(pos, "Base type does not match previous declaration") entry.already_declared_here() - else: - entry.type.base_classes = base_classes - if templates or entry.type.templates: - if templates != entry.type.templates: - error(pos, "Template parameters do not match previous declaration") + else: + entry.type.base_classes = base_classes + if templates or entry.type.templates: + if templates != entry.type.templates: + error(pos, "Template parameters do not match previous declaration") entry.already_declared_here() - - def declare_inherited_attributes(entry, base_classes): - for base_class in base_classes: - if base_class is PyrexTypes.error_type: - continue - if base_class.scope is None: - error(pos, "Cannot inherit from incomplete type") - else: - declare_inherited_attributes(entry, base_class.base_classes) + + def declare_inherited_attributes(entry, base_classes): + for base_class in base_classes: + if base_class is PyrexTypes.error_type: + continue + if base_class.scope is None: + error(pos, "Cannot inherit from incomplete type") + else: + declare_inherited_attributes(entry, base_class.base_classes) entry.type.scope.declare_inherited_cpp_attributes(base_class) if scope: - declare_inherited_attributes(entry, base_classes) - scope.declare_var(name="this", cname="this", type=PyrexTypes.CPtrType(entry.type), pos=entry.pos) - 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', api = 0, create_wrapper = 0): - if name: - if not cname: + declare_inherited_attributes(entry, base_classes) + scope.declare_var(name="this", cname="this", type=PyrexTypes.CPtrType(entry.type), pos=entry.pos) + 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', api = 0, create_wrapper = 0): + if name: + if not cname: if (self.in_cinclude or visibility == 'public' or visibility == 'extern' or api): - cname = name - else: - cname = self.mangle(Naming.type_prefix, name) + cname = name + else: + cname = self.mangle(Naming.type_prefix, name) if self.is_cpp_class_scope: namespace = self.outer_scope.lookup(self.name).type else: namespace = None type = PyrexTypes.CEnumType(name, cname, typedef_flag, namespace) - else: - type = PyrexTypes.c_anon_enum_type - entry = self.declare_type(name, type, pos, cname = cname, - visibility = visibility, api = api) - entry.create_wrapper = create_wrapper - entry.enum_values = [] - self.sue_entries.append(entry) - return entry - + else: + type = PyrexTypes.c_anon_enum_type + entry = self.declare_type(name, type, pos, cname = cname, + visibility = visibility, api = api) + entry.create_wrapper = create_wrapper + entry.enum_values = [] + self.sue_entries.append(entry) + return entry + def declare_tuple_type(self, pos, components): return self.outer_scope.declare_tuple_type(pos, components) - def declare_var(self, name, type, pos, - cname = None, visibility = 'private', - api = 0, in_pxd = 0, is_cdef = 0): - # Add an entry for a variable. - if not cname: - if visibility != 'private' or api: - cname = name - else: - cname = self.mangle(Naming.var_prefix, name) - if type.is_cpp_class and visibility != 'extern': - type.check_nullary_constructor(pos) - entry = self.declare(name, cname, type, pos, visibility) - entry.is_variable = 1 - if in_pxd and visibility != 'extern': - entry.defined_in_pxd = 1 - entry.used = 1 - if api: - entry.api = 1 - entry.used = 1 - return entry - - def declare_builtin(self, name, pos): - return self.outer_scope.declare_builtin(name, pos) - - def _declare_pyfunction(self, name, pos, visibility='extern', entry=None): - if entry and not entry.type.is_cfunction: - error(pos, "'%s' already declared" % name) - error(entry.pos, "Previous declaration is here") - entry = self.declare_var(name, py_object_type, pos, visibility=visibility) - entry.signature = pyfunction_signature - self.pyfunc_entries.append(entry) - return entry - - def declare_pyfunction(self, name, pos, allow_redefine=False, visibility='extern'): - # Add an entry for a Python function. - entry = self.lookup_here(name) - if not allow_redefine: - return self._declare_pyfunction(name, pos, visibility=visibility, entry=entry) - if entry: - if entry.type.is_unspecified: - entry.type = py_object_type - elif entry.type is not py_object_type: - return self._declare_pyfunction(name, pos, visibility=visibility, entry=entry) - else: # declare entry stub - self.declare_var(name, py_object_type, pos, visibility=visibility) - entry = self.declare_var(None, py_object_type, pos, - cname=name, visibility='private') - entry.name = EncodedString(name) - entry.qualified_name = self.qualify_name(name) - entry.signature = pyfunction_signature - entry.is_anonymous = True - return entry - - def declare_lambda_function(self, lambda_name, pos): - # Add an entry for an anonymous Python function. - func_cname = self.mangle(Naming.lambda_func_prefix + u'funcdef_', lambda_name) - pymethdef_cname = self.mangle(Naming.lambda_func_prefix + u'methdef_', lambda_name) - qualified_name = self.qualify_name(lambda_name) - - entry = self.declare(None, func_cname, py_object_type, pos, 'private') - entry.name = lambda_name - entry.qualified_name = qualified_name - entry.pymethdef_cname = pymethdef_cname - entry.func_cname = func_cname - entry.signature = pyfunction_signature - entry.is_anonymous = True - 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, + def declare_var(self, name, type, pos, + cname = None, visibility = 'private', + api = 0, in_pxd = 0, is_cdef = 0): + # Add an entry for a variable. + if not cname: + if visibility != 'private' or api: + cname = name + else: + cname = self.mangle(Naming.var_prefix, name) + if type.is_cpp_class and visibility != 'extern': + type.check_nullary_constructor(pos) + entry = self.declare(name, cname, type, pos, visibility) + entry.is_variable = 1 + if in_pxd and visibility != 'extern': + entry.defined_in_pxd = 1 + entry.used = 1 + if api: + entry.api = 1 + entry.used = 1 + return entry + + def declare_builtin(self, name, pos): + return self.outer_scope.declare_builtin(name, pos) + + def _declare_pyfunction(self, name, pos, visibility='extern', entry=None): + if entry and not entry.type.is_cfunction: + error(pos, "'%s' already declared" % name) + error(entry.pos, "Previous declaration is here") + entry = self.declare_var(name, py_object_type, pos, visibility=visibility) + entry.signature = pyfunction_signature + self.pyfunc_entries.append(entry) + return entry + + def declare_pyfunction(self, name, pos, allow_redefine=False, visibility='extern'): + # Add an entry for a Python function. + entry = self.lookup_here(name) + if not allow_redefine: + return self._declare_pyfunction(name, pos, visibility=visibility, entry=entry) + if entry: + if entry.type.is_unspecified: + entry.type = py_object_type + elif entry.type is not py_object_type: + return self._declare_pyfunction(name, pos, visibility=visibility, entry=entry) + else: # declare entry stub + self.declare_var(name, py_object_type, pos, visibility=visibility) + entry = self.declare_var(None, py_object_type, pos, + cname=name, visibility='private') + entry.name = EncodedString(name) + entry.qualified_name = self.qualify_name(name) + entry.signature = pyfunction_signature + entry.is_anonymous = True + return entry + + def declare_lambda_function(self, lambda_name, pos): + # Add an entry for an anonymous Python function. + func_cname = self.mangle(Naming.lambda_func_prefix + u'funcdef_', lambda_name) + pymethdef_cname = self.mangle(Naming.lambda_func_prefix + u'methdef_', lambda_name) + qualified_name = self.qualify_name(lambda_name) + + entry = self.declare(None, func_cname, py_object_type, pos, 'private') + entry.name = lambda_name + entry.qualified_name = qualified_name + entry.pymethdef_cname = pymethdef_cname + entry.func_cname = func_cname + entry.signature = pyfunction_signature + entry.is_anonymous = True + 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', api=0, in_pxd=0, defining=0, modifiers=(), utility_code=None, overridable=False): - # Add an entry for a C function. - if not cname: - if visibility != 'private' or api: - cname = name - else: - cname = self.mangle(Naming.func_prefix, name) - entry = self.lookup_here(name) - if entry: + # Add an entry for a C function. + if not cname: + if visibility != 'private' or api: + cname = name + else: + cname = self.mangle(Naming.func_prefix, name) + entry = self.lookup_here(name) + if entry: if not in_pxd and visibility != entry.visibility and visibility == 'extern': # Previously declared, but now extern => treat this # as implementing the function, using the new cname @@ -768,7 +768,7 @@ class Scope(object): visibility = entry.visibility entry.cname = cname entry.func_cname = cname - if visibility != 'private' and visibility != entry.visibility: + if visibility != 'private' and visibility != entry.visibility: warning(pos, "Function '%s' previously declared as '%s', now as '%s'" % (name, entry.visibility, visibility), 1) if overridable != entry.is_overridable: warning(pos, "Function '%s' previously declared as '%s'" % ( @@ -777,48 +777,48 @@ class Scope(object): # Fix with_gil vs nogil. entry.type = entry.type.with_with_gil(type.with_gil) else: - if visibility == 'extern' and entry.visibility == 'extern': - can_override = False - if self.is_cpp(): - can_override = True - elif cname: - # if all alternatives have different cnames, - # it's safe to allow signature overrides - for alt_entry in entry.all_alternatives(): - if not alt_entry.cname or cname == alt_entry.cname: - break # cname not unique! - else: - can_override = True - if can_override: - 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 + if visibility == 'extern' and entry.visibility == 'extern': + can_override = False + if self.is_cpp(): + can_override = True + elif cname: + # if all alternatives have different cnames, + # it's safe to allow signature overrides + for alt_entry in entry.all_alternatives(): + if not alt_entry.cname or cname == alt_entry.cname: + break # cname not unique! + else: + can_override = True + if can_override: + 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 elif not in_pxd and entry.defined_in_pxd and type.compatible_signature_with(entry.type): # TODO: check that this was done by a signature optimisation and not a user error. #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 + 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 entry.is_overridable = overridable - 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 - if utility_code: - assert not entry.utility_code, "duplicate utility code definition in entry %s (%s)" % (name, cname) - entry.utility_code = utility_code + 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 + if utility_code: + assert not entry.utility_code, "duplicate utility code definition in entry %s (%s)" % (name, cname) + entry.utility_code = utility_code if overridable: # names of cpdef functions can be used as variables and can be assigned to var_entry = Entry(name, cname, py_object_type) # FIXME: cname? @@ -827,15 +827,15 @@ class Scope(object): var_entry.is_pyglobal = 1 var_entry.scope = entry.scope entry.as_variable = var_entry - type.entry = entry - return entry - + type.entry = entry + return entry + def add_cfunction(self, name, type, pos, cname, visibility, modifiers, inherited=False): - # 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 + # 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 if inherited or type.is_fused: self.cfunc_entries.append(entry) else: @@ -847,68 +847,68 @@ class Scope(object): break i -= 1 self.cfunc_entries.insert(i, 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: - if entry.type.is_fused and self.fused_to_specific: - return entry.type.specialize(self.fused_to_specific) - 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: + 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: + if entry.type.is_fused and self.fused_to_specific: + return entry.type.specialize(self.fused_to_specific) + 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: arg_types = [arg.type for arg in operands[1:]] res = PyrexTypes.best_match([arg.type for arg in operands[1:]], method.all_alternatives()) - if res is not None: - return res - function = self.lookup("operator%s" % operator) + if res is not None: + return res + function = self.lookup("operator%s" % operator) function_alternatives = [] if function is not None: function_alternatives = function.all_alternatives() @@ -924,34 +924,34 @@ class Scope(object): method_alternatives += method.all_alternatives() if (not method_alternatives) and (not function_alternatives): - return None + return None # select the unique alternatives all_alternatives = list(set(method_alternatives + function_alternatives)) return PyrexTypes.best_match([arg.type for arg in operands], all_alternatives) - - def lookup_operator_for_types(self, pos, operator, types): - from .Nodes import Node - class FakeOperand(Node): - pass - operands = [FakeOperand(pos, type=type) for type in types] - return self.lookup_operator(operator, operands) - - def use_utility_code(self, new_code): - self.global_scope().use_utility_code(new_code) - + + def lookup_operator_for_types(self, pos, operator, types): + from .Nodes import Node + class FakeOperand(Node): + pass + operands = [FakeOperand(pos, type=type) for type in types] + return self.lookup_operator(operator, operands) + + def use_utility_code(self, new_code): + self.global_scope().use_utility_code(new_code) + def use_entry_utility_code(self, entry): self.global_scope().use_entry_utility_code(entry) - def defines_any(self, names): + 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 - + for name in names: + if name in self.entries: + return 1 + return 0 + def defines_any_special(self, names): # Test whether any of the given names are defined as special methods in this scope. for name in names: @@ -959,240 +959,240 @@ class Scope(object): 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() - + 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() + def add_include_file(self, filename, verbatim_include=None, late=False): self.outer_scope.add_include_file(filename, verbatim_include, late) - - -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. - - is_builtin_scope = True - - 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 = {} - + + +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. + + is_builtin_scope = True + + 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 sorted(self.builtin_entries.items()): - cname, type = definition - self.declare_var(name, type, None, cname) - + cname, type = definition + self.declare_var(name, type, None, cname) + def lookup(self, name, language_level=None, str_is_str=None): # 'language_level' and 'str_is_str' are passed by ModuleScope if name == 'str': if str_is_str is None: str_is_str = language_level in (None, 2) if not str_is_str: - name = 'unicode' - return Scope.lookup(self, name) - - 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: - if Options.error_on_unknown_names: - error(pos, "undeclared name not builtin: %s" % name) - else: - warning(pos, "undeclared name not builtin: %s" % name, 2) - + name = 'unicode' + return Scope.lookup(self, name) + + 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: + if Options.error_on_unknown_names: + error(pos, "undeclared name not builtin: %s" % name) + else: + warning(pos, "undeclared name not builtin: %s" % name, 2) + 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', + # 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', 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) + 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.qualified_name = self.qualify_name(name) - var_entry.is_variable = 1 - var_entry.is_builtin = 1 - var_entry.utility_code = utility_code - var_entry.scope = entry.scope - entry.as_variable = var_entry - return entry - - def declare_builtin_type(self, name, cname, utility_code = None, objstruct_cname = None): - name = EncodedString(name) - type = PyrexTypes.BuiltinObjectType(name, cname, objstruct_cname) - scope = CClassScope(name, outer_scope=None, visibility='extern') - scope.directives = {} - if name == 'bool': - type.is_final_type = True - type.set_scope(scope) - 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, + var_entry.is_variable = 1 + var_entry.is_builtin = 1 + var_entry.utility_code = utility_code + var_entry.scope = entry.scope + entry.as_variable = var_entry + return entry + + def declare_builtin_type(self, name, cname, utility_code = None, objstruct_cname = None): + name = EncodedString(name) + type = PyrexTypes.BuiltinObjectType(name, cname, objstruct_cname) + scope = CClassScope(name, outer_scope=None, visibility='extern') + scope.directives = {} + if name == 'bool': + type.is_final_type = True + type.set_scope(scope) + 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 = entry.type.typeptr_cname) var_entry.qualified_name = self.qualify_name(name) - 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 + 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 var_entry.scope = self - if Options.cache_builtins: - var_entry.is_const = True - 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], - "bytearray": ["((PyObject*)&PyByteArray_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], # not in Py3 - - "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 + if Options.cache_builtins: + var_entry.is_const = True + 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], + "bytearray": ["((PyObject*)&PyByteArray_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], # not in Py3 + + "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 # c_includes {key: IncludeCode} C headers or verbatim code to be generated # See process_include() for more documentation - # 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} Set of types for which import code generated - # has_import_star boolean Module contains import * - # cpp boolean Compiling a C++ file - # is_cython_builtin boolean Is this the Cython builtin scope (or a child scope) - # is_package boolean Is this a package module? (__init__) - - is_module_scope = 1 - has_import_star = 0 - is_cython_builtin = 0 + # 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} Set of types for which import code generated + # has_import_star boolean Module contains import * + # cpp boolean Compiling a C++ file + # is_cython_builtin boolean Is this the Cython builtin scope (or a child scope) + # is_package boolean Is this a package module? (__init__) + + is_module_scope = 1 + has_import_star = 0 + is_cython_builtin = 0 old_style_globals = 0 - - def __init__(self, name, parent_module, context): - from . import Builtin - self.parent_module = parent_module - outer_scope = Builtin.builtin_scope - Scope.__init__(self, name, outer_scope, parent_module) - if name == "__init__": - # Treat Spam/__init__.pyx specially, so that when Python loads - # Spam/__init__.so, initSpam() is defined. - self.module_name = parent_module.module_name - self.is_package = True - else: - self.module_name = name - self.is_package = False - self.module_name = EncodedString(self.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 = {} + + def __init__(self, name, parent_module, context): + from . import Builtin + self.parent_module = parent_module + outer_scope = Builtin.builtin_scope + Scope.__init__(self, name, outer_scope, parent_module) + if name == "__init__": + # Treat Spam/__init__.pyx specially, so that when Python loads + # Spam/__init__.so, initSpam() is defined. + self.module_name = parent_module.module_name + self.is_package = True + else: + self.module_name = name + self.is_package = False + self.module_name = EncodedString(self.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.c_includes = {} - self.type_names = dict(outer_scope.type_names) - self.pxd_file_loaded = 0 - self.cimported_modules = [] - self.types_imported = set() - self.included_files = [] - self.has_extern_class = 0 - self.cached_builtins = [] - self.undeclared_cached_builtins = [] - self.namespace_cname = self.module_cname + self.type_names = dict(outer_scope.type_names) + self.pxd_file_loaded = 0 + self.cimported_modules = [] + self.types_imported = set() + self.included_files = [] + self.has_extern_class = 0 + self.cached_builtins = [] + self.undeclared_cached_builtins = [] + self.namespace_cname = self.module_cname self._cached_tuple_types = {} for var_name in ['__builtins__', '__name__', '__file__', '__doc__', '__path__', '__spec__', '__loader__', '__package__', '__cached__']: - self.declare_var(EncodedString(var_name), py_object_type, None) + self.declare_var(EncodedString(var_name), py_object_type, None) self.process_include(Code.IncludeCode("Python.h", initial=True)) - - def qualifying_scope(self): - return self.parent_module - - def global_scope(self): - return self - + + def qualifying_scope(self): + return self.parent_module + + def global_scope(self): + return self + def lookup(self, name, language_level=None, str_is_str=None): - entry = self.lookup_here(name) - if entry is not None: - return entry - + entry = self.lookup_here(name) + if entry is not None: + return entry + if language_level is None: language_level = self.context.language_level if self.context is not None else 3 if str_is_str is None: str_is_str = language_level == 2 or ( self.context is not None and Future.unicode_literals not in self.context.future_directives) - + return self.outer_scope.lookup(name, language_level=language_level, str_is_str=str_is_str) - + def declare_tuple_type(self, pos, components): components = tuple(components) try: @@ -1213,48 +1213,48 @@ class ModuleScope(Scope): ttype.entry = entry return entry - def declare_builtin(self, name, pos): - if not hasattr(builtins, name) \ - and name not in Code.non_portable_builtins_map \ - and name not in Code.uncachable_builtins: - if self.has_import_star: - entry = self.declare_var(name, py_object_type, pos) - return entry - else: - if Options.error_on_unknown_names: - error(pos, "undeclared name not builtin: %s" % name) - else: - warning(pos, "undeclared name not builtin: %s" % name, 2) - # unknown - assume it's builtin and look it up at runtime - entry = self.declare(name, None, py_object_type, pos, 'private') - entry.is_builtin = 1 - return entry - if Options.cache_builtins: - for entry in self.cached_builtins: - if entry.name == name: - return entry + def declare_builtin(self, name, pos): + if not hasattr(builtins, name) \ + and name not in Code.non_portable_builtins_map \ + and name not in Code.uncachable_builtins: + if self.has_import_star: + entry = self.declare_var(name, py_object_type, pos) + return entry + else: + if Options.error_on_unknown_names: + error(pos, "undeclared name not builtin: %s" % name) + else: + warning(pos, "undeclared name not builtin: %s" % name, 2) + # unknown - assume it's builtin and look it up at runtime + entry = self.declare(name, None, py_object_type, pos, 'private') + entry.is_builtin = 1 + return entry + if Options.cache_builtins: + for entry in self.cached_builtins: + if entry.name == name: + return entry if name == 'globals' and not self.old_style_globals: return self.outer_scope.lookup('__Pyx_Globals') else: entry = self.declare(None, None, py_object_type, pos, 'private') - if Options.cache_builtins and name not in Code.uncachable_builtins: - entry.is_builtin = 1 - entry.is_const = 1 # cached - 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 - entry.name = name + if Options.cache_builtins and name not in Code.uncachable_builtins: + entry.is_builtin = 1 + entry.is_const = 1 # cached + 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 + entry.name = name entry.qualified_name = self.builtin_scope().qualify_name(name) - return entry - - def find_module(self, module_name, pos, relative_level=-1): - # 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 entry + + def find_module(self, module_name, pos, relative_level=-1): + # 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. relative_to = None absolute_fallback = False if relative_level is not None and relative_level > 0: @@ -1269,27 +1269,27 @@ class ModuleScope(Scope): relative_to = self.parent_module absolute_fallback = True - module_scope = self.global_scope() - return module_scope.context.find_module( + module_scope = self.global_scope() + return module_scope.context.find_module( module_name, relative_to=relative_to, pos=pos, absolute_fallback=absolute_fallback) - - 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. + + 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. if '.' in name: name, submodule = name.split('.', 1) else: submodule = None - scope = self.lookup_submodule(name) - if not scope: + scope = self.lookup_submodule(name) + if not scope: scope = ModuleScope(name, parent_module=self, context=self.context) - self.module_entries[name] = scope + self.module_entries[name] = scope if submodule: scope = scope.find_submodule(submodule) - return scope - - def lookup_submodule(self, name): - # Return scope for submodule of this module, or None. + return scope + + def lookup_submodule(self, name): + # Return scope for submodule of this module, or None. if '.' in name: name, submodule = name.split('.', 1) else: @@ -1298,7 +1298,7 @@ class ModuleScope(Scope): if submodule and module is not None: module = module.lookup_submodule(submodule) return module - + def add_include_file(self, filename, verbatim_include=None, late=False): """ Add `filename` as include file. Add `verbatim_include` as @@ -1307,7 +1307,7 @@ class ModuleScope(Scope): """ inc = Code.IncludeCode(filename, verbatim_include, late=late) self.process_include(inc) - + def process_include(self, inc): """ Add `inc`, which is an instance of `IncludeCode`, to this @@ -1339,142 +1339,142 @@ class ModuleScope(Scope): inc.dict_update(self.c_includes, key) inc = self.c_includes[key] - def add_imported_module(self, scope): - if scope not in self.cimported_modules: + def add_imported_module(self, scope): + if scope not in self.cimported_modules: for inc in scope.c_includes.values(): self.process_include(inc) - self.cimported_modules.append(scope) - for m in scope.cimported_modules: - self.add_imported_module(m) - - def add_imported_entry(self, name, entry, pos): + 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.is_pyglobal: # Allow cimports to follow imports. entry.is_variable = True - 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 - else: - entry = self.declare_var(name, py_object_type, 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 + else: + entry = self.declare_var(name, py_object_type, pos) entry.is_variable = 0 - entry.as_module = scope - self.add_imported_module(scope) - return entry - - def declare_var(self, name, type, pos, - cname = None, visibility = 'private', - api = 0, in_pxd = 0, 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. - 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") - - if not cname: - defining = not in_pxd - if visibility == 'extern' or (visibility == 'public' and defining): - cname = name - else: - cname = self.mangle(Naming.var_prefix, name) - - entry = self.lookup_here(name) - if entry and entry.defined_in_pxd: - #if visibility != 'private' and visibility != entry.visibility: - # warning(pos, "Variable '%s' previously declared as '%s'" % (name, entry.visibility), 1) - if not entry.type.same_as(type): - if visibility == 'extern' and entry.visibility == 'extern': - warning(pos, "Variable '%s' type does not match previous declaration" % name, 1) - entry.type = type - #else: - # error(pos, "Variable '%s' type does not match previous declaration" % name) - if entry.visibility != "private": - mangled_cname = self.mangle(Naming.var_prefix, name) - if entry.cname == mangled_cname: - cname = name - entry.cname = name - if not entry.is_implemented: - entry.is_implemented = True - return entry - - entry = Scope.declare_var(self, name, type, pos, - cname=cname, visibility=visibility, - api=api, in_pxd=in_pxd, is_cdef=is_cdef) - if is_cdef: - entry.is_cglobal = 1 + entry.as_module = scope + self.add_imported_module(scope) + return entry + + def declare_var(self, name, type, pos, + cname = None, visibility = 'private', + api = 0, in_pxd = 0, 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. + 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") + + if not cname: + defining = not in_pxd + if visibility == 'extern' or (visibility == 'public' and defining): + cname = name + else: + cname = self.mangle(Naming.var_prefix, name) + + entry = self.lookup_here(name) + if entry and entry.defined_in_pxd: + #if visibility != 'private' and visibility != entry.visibility: + # warning(pos, "Variable '%s' previously declared as '%s'" % (name, entry.visibility), 1) + if not entry.type.same_as(type): + if visibility == 'extern' and entry.visibility == 'extern': + warning(pos, "Variable '%s' type does not match previous declaration" % name, 1) + entry.type = type + #else: + # error(pos, "Variable '%s' type does not match previous declaration" % name) + if entry.visibility != "private": + mangled_cname = self.mangle(Naming.var_prefix, name) + if entry.cname == mangled_cname: + cname = name + entry.cname = name + if not entry.is_implemented: + entry.is_implemented = True + return entry + + entry = Scope.declare_var(self, name, type, pos, + cname=cname, visibility=visibility, + api=api, in_pxd=in_pxd, is_cdef=is_cdef) + if is_cdef: + entry.is_cglobal = 1 if entry.type.declaration_value: entry.init = entry.type.declaration_value - self.var_entries.append(entry) - else: - entry.is_pyglobal = 1 - if Options.cimport_from_pyx: - entry.used = 1 - return entry - - def declare_cfunction(self, name, type, pos, + self.var_entries.append(entry) + else: + entry.is_pyglobal = 1 + if Options.cimport_from_pyx: + entry.used = 1 + return entry + + def declare_cfunction(self, name, type, pos, cname=None, visibility='private', api=0, in_pxd=0, defining=0, modifiers=(), utility_code=None, overridable=False): if not defining and 'inline' in modifiers: # TODO(github/1736): Make this an error. warning(pos, "Declarations should not be declared inline.", 1) - # Add an entry for a C function. - if not cname: - if visibility == 'extern' or (visibility == 'public' and defining): - cname = name - else: - cname = self.mangle(Naming.func_prefix, name) + # Add an entry for a C function. + if not cname: + if visibility == 'extern' or (visibility == 'public' and defining): + cname = name + else: + cname = self.mangle(Naming.func_prefix, name) if visibility == 'extern' and type.optional_arg_count: error(pos, "Extern functions cannot have default arguments values.") - entry = self.lookup_here(name) - if entry and entry.defined_in_pxd: - if entry.visibility != "private": - mangled_cname = self.mangle(Naming.var_prefix, name) - if entry.cname == mangled_cname: - cname = name - entry.cname = cname - entry.func_cname = cname - entry = Scope.declare_cfunction( - self, name, type, pos, + entry = self.lookup_here(name) + if entry and entry.defined_in_pxd: + if entry.visibility != "private": + mangled_cname = self.mangle(Naming.var_prefix, name) + if entry.cname == mangled_cname: + cname = name + entry.cname = cname + entry.func_cname = cname + entry = Scope.declare_cfunction( + self, name, type, pos, cname=cname, visibility=visibility, api=api, in_pxd=in_pxd, defining=defining, modifiers=modifiers, utility_code=utility_code, overridable=overridable) - 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) - + 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 use_entry_utility_code(self, entry): if entry is None: return @@ -1488,329 +1488,329 @@ class ModuleScope(Scope): typeobj_cname=None, typeptr_cname=None, visibility='private', typedef_flag=0, api=0, check_size=None, buffer_defaults=None, shadow=0): - # 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 not (visibility == 'public' or api): - warning(pos, "ctypedef only valid for 'extern' , 'public', and 'api'", 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 and not shadow: - 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 or shadow: + # 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 not (visibility == 'public' or api): + warning(pos, "ctypedef only valid for 'extern' , 'public', and 'api'", 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 and not shadow: + 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 or shadow: type = PyrexTypes.PyExtensionType( name, typedef_flag, base_type, visibility == 'extern', check_size=check_size) - 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 - if typeptr_cname: - type.typeptr_cname = typeptr_cname - else: - type.typeptr_cname = self.mangle(Naming.typeptr_prefix, name) - entry = self.declare_type(name, type, pos, visibility = visibility, - defining = 0, shadow = shadow) - 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) - scope.directives = self.directives.copy() - 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: - 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 - - if self.directives.get('final'): - entry.type.is_final_type = True - - # cdef classes are always exported, but we need to set it to - # distinguish between unused Cython utility code extension classes - entry.used = True - - # - # Return new or existing entry - # - return entry - - 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: - # one special case here: when inheriting from builtin - # types, the methods may also be built-in, in which - # case they won't need a vtable - entry_count = len(type.scope.cfunc_entries) - base_type = type.base_type - while base_type: - # FIXME: this will break if we ever get non-inherited C methods - if not base_type.scope or entry_count > len(base_type.scope.cfunc_entries): - break - if base_type.is_builtin_type: - # builtin base type defines all methods => no vtable needed - return - base_type = base_type.base_type - #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_class(self, entry): - 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_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) - self.check_c_class(entry) - - 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. - from . import Builtin - var_entry = Entry(name = entry.name, - type = Builtin.type_type, - pos = entry.pos, + 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 + if typeptr_cname: + type.typeptr_cname = typeptr_cname + else: + type.typeptr_cname = self.mangle(Naming.typeptr_prefix, name) + entry = self.declare_type(name, type, pos, visibility = visibility, + defining = 0, shadow = shadow) + 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) + scope.directives = self.directives.copy() + 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: + 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 + + if self.directives.get('final'): + entry.type.is_final_type = True + + # cdef classes are always exported, but we need to set it to + # distinguish between unused Cython utility code extension classes + entry.used = True + + # + # Return new or existing entry + # + return entry + + 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: + # one special case here: when inheriting from builtin + # types, the methods may also be built-in, in which + # case they won't need a vtable + entry_count = len(type.scope.cfunc_entries) + base_type = type.base_type + while base_type: + # FIXME: this will break if we ever get non-inherited C methods + if not base_type.scope or entry_count > len(base_type.scope.cfunc_entries): + break + if base_type.is_builtin_type: + # builtin base type defines all methods => no vtable needed + return + base_type = base_type.base_type + #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_class(self, entry): + 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_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) + self.check_c_class(entry) + + 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. + from . import Builtin + var_entry = Entry(name = entry.name, + type = Builtin.type_type, + pos = entry.pos, cname = entry.type.typeptr_cname) var_entry.qualified_name = entry.qualified_name - var_entry.is_variable = 1 - var_entry.is_cglobal = 1 - var_entry.is_readonly = 1 + var_entry.is_variable = 1 + var_entry.is_cglobal = 1 + var_entry.is_readonly = 1 var_entry.scope = entry.scope - 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): - - # Does the function have a 'with gil:' block? - has_with_gil_block = False - - # Transient attribute, used for symbol table variable declarations - _in_with_gil_block = False - - 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) - return entry - - def declare_var(self, name, type, pos, - cname = None, visibility = 'private', - api = 0, in_pxd = 0, 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=cname, visibility=visibility, - api=api, in_pxd=in_pxd, is_cdef=is_cdef) + 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): + + # Does the function have a 'with gil:' block? + has_with_gil_block = False + + # Transient attribute, used for symbol table variable declarations + _in_with_gil_block = False + + 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) + return entry + + def declare_var(self, name, type, pos, + cname = None, visibility = 'private', + api = 0, in_pxd = 0, 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=cname, visibility=visibility, + api=api, in_pxd=in_pxd, is_cdef=is_cdef) if entry.type.declaration_value: entry.init = entry.type.declaration_value - entry.is_local = 1 - - entry.in_with_gil_block = self._in_with_gil_block - 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 declare_nonlocal(self, name, pos): - # Pull entry from outer scope into local scope - orig_entry = self.lookup_here(name) - if orig_entry and orig_entry.scope is self and not orig_entry.from_closure: - error(pos, "'%s' redeclared as nonlocal" % name) + entry.is_local = 1 + + entry.in_with_gil_block = self._in_with_gil_block + 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 declare_nonlocal(self, name, pos): + # Pull entry from outer scope into local scope + orig_entry = self.lookup_here(name) + if orig_entry and orig_entry.scope is self and not orig_entry.from_closure: + error(pos, "'%s' redeclared as nonlocal" % name) orig_entry.already_declared_here() - else: - entry = self.lookup(name) - if entry is None or not entry.from_closure: - error(pos, "no binding for nonlocal '%s' found" % name) - - 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: + else: + entry = self.lookup(name) + if entry is None or not entry.from_closure: + error(pos, "no binding for nonlocal '%s' found" % name) + + 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: entry_scope = entry.scope while entry_scope.is_genexpr_scope: entry_scope = entry_scope.outer_scope if entry_scope is not self and entry_scope.is_closure_scope: - if hasattr(entry.scope, "scope_class"): - raise InternalError("lookup() after scope class created.") - # The actual c fragment for the different scopes differs - # on the outside and inside, so we make a new entry - entry.in_closure = True - inner_entry = InnerEntry(entry, self) - inner_entry.is_variable = True - self.entries[name] = inner_entry - return inner_entry - return entry - - def mangle_closure_cnames(self, outer_scope_cname): + if hasattr(entry.scope, "scope_class"): + raise InternalError("lookup() after scope class created.") + # The actual c fragment for the different scopes differs + # on the outside and inside, so we make a new entry + entry.in_closure = True + inner_entry = InnerEntry(entry, self) + inner_entry.is_variable = True + self.entries[name] = inner_entry + return inner_entry + return entry + + def mangle_closure_cnames(self, outer_scope_cname): for scope in self.iter_local_scopes(): for entry in scope.entries.values(): if entry.from_closure: @@ -1824,25 +1824,25 @@ class LocalScope(Scope): elif entry.in_closure: entry.original_cname = entry.cname entry.cname = "%s->%s" % (Naming.cur_scope_cname, entry.cname) - - -class GeneratorExpressionScope(Scope): - """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). - """ + + +class GeneratorExpressionScope(Scope): + """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). + """ is_genexpr_scope = True - def __init__(self, outer_scope): + def __init__(self, outer_scope): parent_scope = outer_scope # TODO: also ignore class scopes? while parent_scope.is_genexpr_scope: parent_scope = parent_scope.parent_scope name = parent_scope.global_scope().next_id(Naming.genexpr_id_ref) Scope.__init__(self, name, outer_scope, parent_scope) - self.directives = outer_scope.directives - self.genexp_prefix = "%s%d%s" % (Naming.pyrex_prefix, len(name), name) - + self.directives = outer_scope.directives + self.genexp_prefix = "%s%d%s" % (Naming.pyrex_prefix, len(name), name) + # Class/ExtType scopes are filled at class creation time, i.e. from the # module init function or surrounding function. while outer_scope.is_genexpr_scope or outer_scope.is_c_class_scope or outer_scope.is_py_class_scope: @@ -1850,333 +1850,333 @@ class GeneratorExpressionScope(Scope): self.var_entries = outer_scope.var_entries # keep declarations outside outer_scope.subscopes.add(self) - def mangle(self, prefix, name): - return '%s%s' % (self.genexp_prefix, self.parent_scope.mangle(prefix, name)) - - def declare_var(self, name, type, pos, - cname = None, visibility = 'private', - api = 0, in_pxd = 0, 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 parent scope needs to generate code for the variable, but - # this scope must hold its name exclusively - cname = '%s%s' % (self.genexp_prefix, self.parent_scope.mangle(Naming.var_prefix, name or self.next_id())) - entry = self.declare(name, cname, type, pos, visibility) + def mangle(self, prefix, name): + return '%s%s' % (self.genexp_prefix, self.parent_scope.mangle(prefix, name)) + + def declare_var(self, name, type, pos, + cname = None, visibility = 'private', + api = 0, in_pxd = 0, 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 parent scope needs to generate code for the variable, but + # this scope must hold its name exclusively + cname = '%s%s' % (self.genexp_prefix, self.parent_scope.mangle(Naming.var_prefix, name or self.next_id())) + entry = self.declare(name, cname, type, pos, visibility) entry.is_variable = True if self.parent_scope.is_module_scope: entry.is_cglobal = True else: entry.is_local = True entry.in_subscope = True - self.var_entries.append(entry) - self.entries[name] = entry - return entry - - def declare_pyfunction(self, name, pos, allow_redefine=False): - return self.outer_scope.declare_pyfunction( - name, pos, allow_redefine) - - def declare_lambda_function(self, func_cname, pos): - return self.outer_scope.declare_lambda_function(func_cname, pos) - - def add_lambda_def(self, def_node): - return self.outer_scope.add_lambda_def(def_node) - - -class ClosureScope(LocalScope): - - is_closure_scope = True - - def __init__(self, name, scope_name, outer_scope, parent_scope=None): - LocalScope.__init__(self, name, outer_scope, parent_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, allow_redefine=False): - return LocalScope.declare_pyfunction(self, name, pos, allow_redefine, visibility='private') - - -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', - api = 0, in_pxd = 0, is_cdef = 0, + self.var_entries.append(entry) + self.entries[name] = entry + return entry + + def declare_pyfunction(self, name, pos, allow_redefine=False): + return self.outer_scope.declare_pyfunction( + name, pos, allow_redefine) + + def declare_lambda_function(self, func_cname, pos): + return self.outer_scope.declare_lambda_function(func_cname, pos) + + def add_lambda_def(self, def_node): + return self.outer_scope.add_lambda_def(def_node) + + +class ClosureScope(LocalScope): + + is_closure_scope = True + + def __init__(self, name, scope_name, outer_scope, parent_scope=None): + LocalScope.__init__(self, name, outer_scope, parent_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, allow_redefine=False): + return LocalScope.declare_pyfunction(self, name, pos, allow_redefine, visibility='private') + + +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', + api = 0, in_pxd = 0, is_cdef = 0, allow_pyobject=False, allow_memoryview=False): - # 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: + # 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") elif type.is_memoryviewslice and not allow_memoryview: # Memory views wrap their buffer owner as a Python object. error(pos, "C struct/union member cannot be a memory view") - if visibility != 'private': + if visibility != 'private': error(pos, "C struct/union member cannot be declared %s" % visibility) - return entry - - def declare_cfunction(self, name, type, pos, + return entry + + def declare_cfunction(self, name, type, pos, cname=None, visibility='private', api=0, in_pxd=0, defining=0, modifiers=(), overridable=False): # currently no utility code ... if overridable: error(pos, "C struct/union member cannot be declared 'cpdef'") - return self.declare_var(name, type, pos, - cname=cname, visibility=visibility) - - -class ClassScope(Scope): - # Abstract base class for namespace of - # Python class or extension type. - # - # class_name string Python 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 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 members 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. - entry = Entry( - "classmethod", - "__Pyx_Method_ClassMethod", - PyrexTypes.CFuncType( - py_object_type, - [PyrexTypes.CFuncTypeArg("", py_object_type, None)], 0, 0)) - entry.utility_code_definition = Code.UtilityCode.load_cached("ClassMethod", "CythonFunction.c") + return self.declare_var(name, type, pos, + cname=cname, visibility=visibility) + + +class ClassScope(Scope): + # Abstract base class for namespace of + # Python class or extension type. + # + # class_name string Python 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 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 members 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. + entry = Entry( + "classmethod", + "__Pyx_Method_ClassMethod", + PyrexTypes.CFuncType( + py_object_type, + [PyrexTypes.CFuncTypeArg("", py_object_type, None)], 0, 0)) + entry.utility_code_definition = Code.UtilityCode.load_cached("ClassMethod", "CythonFunction.c") self.use_entry_utility_code(entry) - 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 mangle_class_private_name(self, name): - return self.mangle_special_name(name) - - def mangle_special_name(self, name): - if name and name.startswith('__') and not name.endswith('__'): - name = EncodedString('_%s%s' % (self.class_name.lstrip('_'), name)) - return name - - def lookup_here(self, name): - name = self.mangle_special_name(name) - return ClassScope.lookup_here(self, name) - - def declare_var(self, name, type, pos, - cname = None, visibility = 'private', - api = 0, in_pxd = 0, is_cdef = 0): - name = self.mangle_special_name(name) - 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=cname, visibility=visibility, - api=api, in_pxd=in_pxd, is_cdef=is_cdef) - entry.is_pyglobal = 1 - entry.is_pyclass_attr = 1 - return entry - - def declare_nonlocal(self, name, pos): - # Pull entry from outer scope into local scope - orig_entry = self.lookup_here(name) - if orig_entry and orig_entry.scope is self and not orig_entry.from_closure: - error(pos, "'%s' redeclared as nonlocal" % name) + 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 mangle_class_private_name(self, name): + return self.mangle_special_name(name) + + def mangle_special_name(self, name): + if name and name.startswith('__') and not name.endswith('__'): + name = EncodedString('_%s%s' % (self.class_name.lstrip('_'), name)) + return name + + def lookup_here(self, name): + name = self.mangle_special_name(name) + return ClassScope.lookup_here(self, name) + + def declare_var(self, name, type, pos, + cname = None, visibility = 'private', + api = 0, in_pxd = 0, is_cdef = 0): + name = self.mangle_special_name(name) + 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=cname, visibility=visibility, + api=api, in_pxd=in_pxd, is_cdef=is_cdef) + entry.is_pyglobal = 1 + entry.is_pyclass_attr = 1 + return entry + + def declare_nonlocal(self, name, pos): + # Pull entry from outer scope into local scope + orig_entry = self.lookup_here(name) + if orig_entry and orig_entry.scope is self and not orig_entry.from_closure: + error(pos, "'%s' redeclared as nonlocal" % name) orig_entry.already_declared_here() - else: - entry = self.lookup(name) - if entry is None: - error(pos, "no binding for nonlocal '%s' found" % name) - else: - # FIXME: this works, but it's unclear if it's the - # right thing to do - self.entries[name] = 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 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? - # has_memoryview_attrs boolean Any memory view attributes? + else: + entry = self.lookup(name) + if entry is None: + error(pos, "no binding for nonlocal '%s' found" % name) + else: + # FIXME: this works, but it's unclear if it's the + # right thing to do + self.entries[name] = 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 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? + # has_memoryview_attrs boolean Any memory view attributes? # has_cpp_class_attrs boolean Any (non-pointer) C++ attributes? - # has_cyclic_pyobject_attrs boolean Any PyObject attributes that may need GC? - # 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 + # has_cyclic_pyobject_attrs boolean Any PyObject attributes that may need GC? + # 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 is_closure_class_scope = False - - has_pyobject_attrs = False - has_memoryview_attrs = False + + has_pyobject_attrs = False + has_memoryview_attrs = False has_cpp_class_attrs = False - has_cyclic_pyobject_attrs = False - defined = False - implemented = False - - 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.property_entries = [] - self.inherited_var_entries = [] - - 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. + has_cyclic_pyobject_attrs = False + defined = False + implemented = False + + 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.property_entries = [] + self.inherited_var_entries = [] + + 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. if self.has_cyclic_pyobject_attrs and not self.directives.get('no_gc', False): - return True - base_type = self.parent_type.base_type - if base_type and base_type.scope is not None: - return base_type.scope.needs_gc() - elif self.parent_type.is_builtin_type: - return not self.parent_type.is_gc_simple - return False - - def needs_tp_clear(self): - """ - Do we need to generate an implementation for the tp_clear slot? Can - be disabled to keep references for the __dealloc__ cleanup function. - """ - return self.needs_gc() and not self.directives.get('no_gc_clear', False) - - def get_refcounted_entries(self, include_weakref=False, - include_gc_simple=True): - py_attrs = [] - py_buffers = [] - memoryview_slices = [] - - for entry in self.var_entries: - if entry.type.is_pyobject: + return True + base_type = self.parent_type.base_type + if base_type and base_type.scope is not None: + return base_type.scope.needs_gc() + elif self.parent_type.is_builtin_type: + return not self.parent_type.is_gc_simple + return False + + def needs_tp_clear(self): + """ + Do we need to generate an implementation for the tp_clear slot? Can + be disabled to keep references for the __dealloc__ cleanup function. + """ + return self.needs_gc() and not self.directives.get('no_gc_clear', False) + + def get_refcounted_entries(self, include_weakref=False, + include_gc_simple=True): + py_attrs = [] + py_buffers = [] + memoryview_slices = [] + + for entry in self.var_entries: + if entry.type.is_pyobject: if include_weakref or (self.is_closure_class_scope or entry.name != "__weakref__"): - if include_gc_simple or not entry.type.is_gc_simple: - py_attrs.append(entry) - elif entry.type == PyrexTypes.c_py_buffer_type: - py_buffers.append(entry) - elif entry.type.is_memoryviewslice: - memoryview_slices.append(entry) - - have_entries = py_attrs or py_buffers or memoryview_slices - return have_entries, (py_attrs, py_buffers, memoryview_slices) - - def declare_var(self, name, type, pos, - cname = None, visibility = 'private', - api = 0, in_pxd = 0, 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 include_gc_simple or not entry.type.is_gc_simple: + py_attrs.append(entry) + elif entry.type == PyrexTypes.c_py_buffer_type: + py_buffers.append(entry) + elif entry.type.is_memoryviewslice: + memoryview_slices.append(entry) + + have_entries = py_attrs or py_buffers or memoryview_slices + return have_entries, (py_attrs, py_buffers, memoryview_slices) + + def declare_var(self, name, type, pos, + cname = None, visibility = 'private', + api = 0, in_pxd = 0, 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 not self.is_closure_class_scope and 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': - type.check_nullary_constructor(pos) - self.use_utility_code(Code.UtilityCode("#include <new>")) - entry = self.declare(name, cname, type, pos, visibility) - entry.is_variable = 1 - self.var_entries.append(entry) - if type.is_memoryviewslice: - self.has_memoryview_attrs = True + 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': + type.check_nullary_constructor(pos) + self.use_utility_code(Code.UtilityCode("#include <new>")) + entry = self.declare(name, cname, type, pos, visibility) + entry.is_variable = 1 + self.var_entries.append(entry) + if type.is_memoryviewslice: + self.has_memoryview_attrs = True elif type.is_cpp_class: self.has_cpp_class_attrs = True elif type.is_pyobject and (self.is_closure_class_scope or name != '__weakref__'): - self.has_pyobject_attrs = True - if (not type.is_builtin_type - or not type.scope or type.scope.needs_gc()): - self.has_cyclic_pyobject_attrs = True - if visibility not in ('private', 'public', 'readonly'): - error(pos, - "Attribute of extension type cannot be declared %s" % visibility) - if visibility in ('public', 'readonly'): - # 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). - entry.needs_property = True + self.has_pyobject_attrs = True + if (not type.is_builtin_type + or not type.scope or type.scope.needs_gc()): + self.has_cyclic_pyobject_attrs = True + if visibility not in ('private', 'public', 'readonly'): + error(pos, + "Attribute of extension type cannot be declared %s" % visibility) + if visibility in ('public', 'readonly'): + # 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). + entry.needs_property = True if not self.is_closure_class_scope and name == "__weakref__": - error(pos, "Special attribute __weakref__ cannot be exposed to Python") + error(pos, "Special attribute __weakref__ cannot be exposed to Python") if not (type.is_pyobject or type.can_coerce_to_pyobject(self)): # we're not testing for coercion *from* Python here - that would fail later error(pos, "C attribute of type '%s' cannot be accessed from Python" % type) - else: - entry.needs_property = False - 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=cname, visibility=visibility, - api=api, in_pxd=in_pxd, is_cdef=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, allow_redefine=False): - # Add an entry for a method. + else: + entry.needs_property = False + 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=cname, visibility=visibility, + api=api, in_pxd=in_pxd, is_cdef=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, allow_redefine=False): + # Add an entry for a method. if name in richcmp_special_methods: if self.lookup_here('__richcmp__'): error(pos, "Cannot define both % and __richcmp__" % name) @@ -2184,67 +2184,67 @@ class CClassScope(ClassScope): for n in richcmp_special_methods: if self.lookup_here(n): error(pos, "Cannot define both % and __richcmp__" % n) - if name == "__new__": - error(pos, "__new__ method of extension type will change semantics " - "in a future version of Pyrex and Cython. Use __cinit__ instead.") - 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__": + error(pos, "__new__ method of extension type will change semantics " + "in a future version of Pyrex and Cython. Use __cinit__ instead.") + 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 not self.is_closure_class_scope and name == "__new__": - name = EncodedString("__cinit__") - entry = ClassScope.lookup_here(self, name) - if entry and entry.is_builtin_cmethod: - if not self.parent_type.is_builtin_type: - # For subtypes of builtin types, we can only return - # optimised C methods if the type if final. - # Otherwise, subtypes may choose to override the - # method, but the optimisation would prevent the - # subtype method from being called. - if not self.parent_type.is_final_type: - return None - return entry - - def declare_cfunction(self, name, type, pos, + name = EncodedString("__cinit__") + entry = ClassScope.lookup_here(self, name) + if entry and entry.is_builtin_cmethod: + if not self.parent_type.is_builtin_type: + # For subtypes of builtin types, we can only return + # optimised C methods if the type if final. + # Otherwise, subtypes may choose to override the + # method, but the optimisation would prevent the + # subtype method from being called. + if not self.parent_type.is_final_type: + return None + return entry + + def declare_cfunction(self, name, type, pos, cname=None, visibility='private', api=0, in_pxd=0, defining=0, modifiers=(), utility_code=None, overridable=False): - if get_special_method_signature(name) and not self.parent_type.is_builtin_type: - error(pos, "Special methods must be declared with 'def', not 'cdef'") - args = type.args - if not type.is_static_method: - 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 cname is None: - cname = c_safe_identifier(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 entry.is_final_cmethod and entry.is_inherited: - error(pos, "Overriding final methods is not allowed") - elif type.same_c_signature_as(entry.type, as_cmethod = 1) and type.nogil == entry.type.nogil: + if get_special_method_signature(name) and not self.parent_type.is_builtin_type: + error(pos, "Special methods must be declared with 'def', not 'cdef'") + args = type.args + if not type.is_static_method: + 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 cname is None: + cname = c_safe_identifier(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 entry.is_final_cmethod and entry.is_inherited: + error(pos, "Overriding final methods is not allowed") + elif type.same_c_signature_as(entry.type, as_cmethod = 1) and type.nogil == entry.type.nogil: # Fix with_gil vs nogil. entry.type = entry.type.with_with_gil(type.with_gil) - elif type.compatible_signature_with(entry.type, as_cmethod = 1) and type.nogil == entry.type.nogil: + elif type.compatible_signature_with(entry.type, as_cmethod = 1) and type.nogil == entry.type.nogil: if (self.defined and not in_pxd and not type.same_c_signature_as_resolved_type(entry.type, as_cmethod = 1, as_pxd_definition = 1)): # TODO(robertwb): Make this an error. @@ -2254,162 +2254,162 @@ class CClassScope(ClassScope): "This may cause incorrect vtables to be generated." % ( name, self.class_name), 2) warning(entry.pos, "Previous declaration is here", 2) - entry = self.add_cfunction(name, type, pos, cname, visibility='ignore', modifiers=modifiers) - 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" + entry = self.add_cfunction(name, type, pos, cname, visibility='ignore', modifiers=modifiers) + 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 '%s'" % (name, self.class_name)) entry = self.add_cfunction(name, type, pos, cname, visibility, modifiers) - if defining: - entry.func_cname = self.mangle(Naming.func_prefix, name) - entry.utility_code = utility_code - type.entry = entry - - if u'inline' in modifiers: - entry.is_inline_cmethod = True - - if (self.parent_type.is_final_type or entry.is_inline_cmethod or - self.directives.get('final')): - entry.is_final_cmethod = True - entry.final_func_cname = entry.func_cname - - return entry - + if defining: + entry.func_cname = self.mangle(Naming.func_prefix, name) + entry.utility_code = utility_code + type.entry = entry + + if u'inline' in modifiers: + entry.is_inline_cmethod = True + + if (self.parent_type.is_final_type or entry.is_inline_cmethod or + self.directives.get('final')): + entry.is_final_cmethod = True + entry.final_func_cname = entry.func_cname + + return entry + def add_cfunction(self, name, type, pos, cname, visibility, modifiers, inherited=False): - # 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, + # 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, inherited=inherited) - entry.is_cmethod = 1 - entry.prev_entry = prev_entry - return entry - - def declare_builtin_cfunction(self, name, type, cname, utility_code = None): - # overridden methods of builtin types still have their Python - # equivalent that must be accessible to support bound methods - name = EncodedString(name) - entry = self.declare_cfunction(name, type, None, cname, visibility='extern', + entry.is_cmethod = 1 + entry.prev_entry = prev_entry + return entry + + def declare_builtin_cfunction(self, name, type, cname, utility_code = None): + # overridden methods of builtin types still have their Python + # equivalent that must be accessible to support bound methods + name = EncodedString(name) + entry = self.declare_cfunction(name, type, None, cname, visibility='extern', utility_code=utility_code) - var_entry = Entry(name, name, py_object_type) + var_entry = Entry(name, name, py_object_type) var_entry.qualified_name = name - var_entry.is_variable = 1 - var_entry.is_builtin = 1 - var_entry.utility_code = utility_code + var_entry.is_variable = 1 + var_entry.is_builtin = 1 + var_entry.utility_code = utility_code var_entry.scope = entry.scope - entry.as_variable = var_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) - - entries = base_scope.inherited_var_entries + base_scope.var_entries - for base_entry in 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) - - # If the class defined in a pxd, specific entries have not been added. - # Ensure now that the parent (base) scope has specific entries - # Iterate over a copy as get_all_specialized_function_types() will mutate - for base_entry in base_scope.cfunc_entries[:]: - if base_entry.type.is_fused: - base_entry.type.get_all_specialized_function_types() - - for base_entry in base_scope.cfunc_entries: - cname = base_entry.cname - var_entry = base_entry.as_variable - is_builtin = var_entry and var_entry.is_builtin - if not is_builtin: - cname = adapt(cname) - entry = self.add_cfunction(base_entry.name, base_entry.type, - base_entry.pos, cname, + entry.as_variable = var_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) + + entries = base_scope.inherited_var_entries + base_scope.var_entries + for base_entry in 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) + + # If the class defined in a pxd, specific entries have not been added. + # Ensure now that the parent (base) scope has specific entries + # Iterate over a copy as get_all_specialized_function_types() will mutate + for base_entry in base_scope.cfunc_entries[:]: + if base_entry.type.is_fused: + base_entry.type.get_all_specialized_function_types() + + for base_entry in base_scope.cfunc_entries: + cname = base_entry.cname + var_entry = base_entry.as_variable + is_builtin = var_entry and var_entry.is_builtin + if not is_builtin: + cname = adapt(cname) + entry = self.add_cfunction(base_entry.name, base_entry.type, + base_entry.pos, cname, base_entry.visibility, base_entry.func_modifiers, inherited=True) - entry.is_inherited = 1 - if base_entry.is_final_cmethod: - entry.is_final_cmethod = True - entry.is_inline_cmethod = base_entry.is_inline_cmethod - if (self.parent_scope == base_scope.parent_scope or - entry.is_inline_cmethod): - entry.final_func_cname = base_entry.final_func_cname - if is_builtin: - entry.is_builtin_cmethod = True - entry.as_variable = var_entry - if base_entry.utility_code: - entry.utility_code = base_entry.utility_code - - -class CppClassScope(Scope): - # Namespace of a C++ class. - - is_cpp_class_scope = 1 - - default_constructor = None - type = None - - def __init__(self, name, outer_scope, templates=None): - Scope.__init__(self, name, outer_scope, None) - self.directives = outer_scope.directives - self.inherited_var_entries = [] - if templates is not None: - for T in templates: - template_entry = self.declare( - T, T, PyrexTypes.TemplatePlaceholderType(T), None, 'extern') - template_entry.is_type = 1 - - def declare_var(self, name, type, pos, - cname = None, visibility = 'extern', + entry.is_inherited = 1 + if base_entry.is_final_cmethod: + entry.is_final_cmethod = True + entry.is_inline_cmethod = base_entry.is_inline_cmethod + if (self.parent_scope == base_scope.parent_scope or + entry.is_inline_cmethod): + entry.final_func_cname = base_entry.final_func_cname + if is_builtin: + entry.is_builtin_cmethod = True + entry.as_variable = var_entry + if base_entry.utility_code: + entry.utility_code = base_entry.utility_code + + +class CppClassScope(Scope): + # Namespace of a C++ class. + + is_cpp_class_scope = 1 + + default_constructor = None + type = None + + def __init__(self, name, outer_scope, templates=None): + Scope.__init__(self, name, outer_scope, None) + self.directives = outer_scope.directives + self.inherited_var_entries = [] + if templates is not None: + for T in templates: + template_entry = self.declare( + T, T, PyrexTypes.TemplatePlaceholderType(T), None, 'extern') + template_entry.is_type = 1 + + def declare_var(self, name, type, pos, + cname = None, visibility = 'extern', api = 0, in_pxd = 0, is_cdef = 0, defining = 0): - # Add an entry for an attribute. - if not cname: - cname = name - entry = self.lookup_here(name) - if defining and entry is not None: + # Add an entry for an attribute. + if not cname: + cname = name + entry = self.lookup_here(name) + if defining and entry is not None: if entry.type.same_as(type): # Fix with_gil vs nogil. entry.type = entry.type.with_with_gil(type.with_gil) elif type.is_cfunction and type.compatible_signature_with(entry.type): entry.type = type else: - error(pos, "Function signature does not match previous declaration") - else: - entry = self.declare(name, cname, type, pos, visibility) - entry.is_variable = 1 - if type.is_cfunction and self.type: + error(pos, "Function signature does not match previous declaration") + else: + entry = self.declare(name, cname, type, pos, visibility) + entry.is_variable = 1 + if type.is_cfunction and self.type: if not self.type.get_fused_types(): entry.func_cname = "%s::%s" % (self.type.empty_declaration_code(), cname) - if name != "this" and (defining or name != "<init>"): - self.var_entries.append(entry) - return entry - - def declare_cfunction(self, name, type, pos, + if name != "this" and (defining or name != "<init>"): + self.var_entries.append(entry) + return entry + + def declare_cfunction(self, name, type, pos, cname=None, visibility='extern', api=0, in_pxd=0, defining=0, modifiers=(), utility_code=None, overridable=False): class_name = self.name.split('::')[-1] if name in (class_name, '__init__') and cname is None: cname = "%s__init__%s" % (Naming.func_prefix, class_name) - name = '<init>' + name = '<init>' type.return_type = PyrexTypes.CVoidType() # This is called by the actual constructor, but need to support # arguments that cannot by called by value. @@ -2421,9 +2421,9 @@ class CppClassScope(Scope): else: return arg type.args = [maybe_ref(arg) for arg in type.args] - elif name == '__dealloc__' and cname is None: + elif name == '__dealloc__' and cname is None: cname = "%s__dealloc__%s" % (Naming.func_prefix, class_name) - name = '<del>' + name = '<del>' type.return_type = PyrexTypes.CVoidType() if name in ('<init>', '<del>') and type.nogil: for base in self.type.base_classes: @@ -2431,16 +2431,16 @@ class CppClassScope(Scope): if base_entry and not base_entry.type.nogil: error(pos, "Constructor cannot be called without GIL unless all base constructors can also be called without GIL") error(base_entry.pos, "Base constructor defined here.") - prev_entry = self.lookup_here(name) - entry = self.declare_var(name, type, pos, - defining=defining, - cname=cname, visibility=visibility) - if prev_entry and not defining: - entry.overloaded_alternatives = prev_entry.all_alternatives() - entry.utility_code = utility_code - type.entry = entry - return entry - + prev_entry = self.lookup_here(name) + entry = self.declare_var(name, type, pos, + defining=defining, + cname=cname, visibility=visibility) + if prev_entry and not defining: + entry.overloaded_alternatives = prev_entry.all_alternatives() + entry.utility_code = utility_code + type.entry = entry + return entry + def declare_inherited_cpp_attributes(self, base_class): base_scope = base_class.scope template_type = base_class @@ -2450,103 +2450,103 @@ class CppClassScope(Scope): base_templates = [T.name for T in template_type.templates] else: base_templates = () - # 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: + # 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: #constructor/destructor is not inherited if base_entry.name in ("<init>", "<del>"): - continue - #print base_entry.name, self.entries - if base_entry.name in self.entries: - base_entry.name # FIXME: is there anything to do in this case? - entry = self.declare(base_entry.name, base_entry.cname, - base_entry.type, None, 'extern') - entry.is_variable = 1 + continue + #print base_entry.name, self.entries + if base_entry.name in self.entries: + base_entry.name # FIXME: is there anything to do in this case? + entry = self.declare(base_entry.name, base_entry.cname, + base_entry.type, None, 'extern') + entry.is_variable = 1 entry.is_inherited = 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, + 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, api=0, modifiers=base_entry.func_modifiers, utility_code=base_entry.utility_code) - entry.is_inherited = 1 + entry.is_inherited = 1 for base_entry in base_scope.type_entries: if base_entry.name not in base_templates: entry = self.declare_type(base_entry.name, base_entry.type, base_entry.pos, base_entry.cname, base_entry.visibility) entry.is_inherited = 1 - - def specialize(self, values, type_entry): - scope = CppClassScope(self.name, self.outer_scope) - scope.type = type_entry - for entry in self.entries.values(): - if entry.is_type: - scope.declare_type(entry.name, - entry.type.specialize(values), - entry.pos, - entry.cname, - template=1) - elif entry.type.is_cfunction: - for e in entry.all_alternatives(): - scope.declare_cfunction(e.name, - e.type.specialize(values), - e.pos, - e.cname, + + def specialize(self, values, type_entry): + scope = CppClassScope(self.name, self.outer_scope) + scope.type = type_entry + for entry in self.entries.values(): + if entry.is_type: + scope.declare_type(entry.name, + entry.type.specialize(values), + entry.pos, + entry.cname, + template=1) + elif entry.type.is_cfunction: + for e in entry.all_alternatives(): + scope.declare_cfunction(e.name, + e.type.specialize(values), + e.pos, + e.cname, utility_code=e.utility_code) - else: - scope.declare_var(entry.name, - entry.type.specialize(values), - entry.pos, - entry.cname, - entry.visibility) - - return scope - - -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, allow_redefine=False): - # 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 - - -class CConstScope(Scope): - - def __init__(self, const_base_type_scope): - Scope.__init__( - self, - 'const_' + const_base_type_scope.name, - const_base_type_scope.outer_scope, - const_base_type_scope.parent_scope) - self.const_base_type_scope = const_base_type_scope - - def lookup_here(self, name): - entry = self.const_base_type_scope.lookup_here(name) - if entry is not None: - entry = copy.copy(entry) - entry.type = PyrexTypes.c_const_type(entry.type) - return entry - -class TemplateScope(Scope): - def __init__(self, name, outer_scope): - Scope.__init__(self, name, outer_scope, None) - self.directives = outer_scope.directives + else: + scope.declare_var(entry.name, + entry.type.specialize(values), + entry.pos, + entry.cname, + entry.visibility) + + return scope + + +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, allow_redefine=False): + # 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 + + +class CConstScope(Scope): + + def __init__(self, const_base_type_scope): + Scope.__init__( + self, + 'const_' + const_base_type_scope.name, + const_base_type_scope.outer_scope, + const_base_type_scope.parent_scope) + self.const_base_type_scope = const_base_type_scope + + def lookup_here(self, name): + entry = self.const_base_type_scope.lookup_here(name) + if entry is not None: + entry = copy.copy(entry) + entry.type = PyrexTypes.c_const_type(entry.type) + return entry + +class TemplateScope(Scope): + def __init__(self, name, outer_scope): + Scope.__init__(self, name, outer_scope, None) + self.directives = outer_scope.directives |