| Index: third_party/cython/src/Cython/Compiler/Symtab.py
|
| diff --git a/third_party/cython/src/Cython/Compiler/Symtab.py b/third_party/cython/src/Cython/Compiler/Symtab.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..8db1e6db7533798930bfc73e3d4a078db374300b
|
| --- /dev/null
|
| +++ b/third_party/cython/src/Cython/Compiler/Symtab.py
|
| @@ -0,0 +1,2248 @@
|
| +#
|
| +# Symbol Table
|
| +#
|
| +
|
| +import copy
|
| +import re
|
| +from Errors import warning, error, InternalError
|
| +from StringEncoding import EncodedString
|
| +import Options, Naming
|
| +import PyrexTypes
|
| +from PyrexTypes import py_object_type, unspecified_type
|
| +from TypeSlots import \
|
| + pyfunction_signature, pymethod_signature, \
|
| + get_special_method_signature, get_property_accessor_signature
|
| +import Code
|
| +import __builtin__ as builtins
|
| +
|
| +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 == '__weakref__'))
|
| + 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
|
| + # 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
|
| + # 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 necesarry.
|
| + # 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 = ""
|
| + 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
|
| + 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 redeclared(self, pos):
|
| + error(pos, "'%s' does not match previous declaration" % self.name)
|
| + error(self.pos, "Previous declaration is here")
|
| +
|
| + def all_alternatives(self):
|
| + return [self] + self.overloaded_alternatives
|
| +
|
| + def all_entries(self):
|
| + return [self] + self.inner_entries
|
| +
|
| +
|
| +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_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
|
| +
|
| + 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)
|
| + 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.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.return_type = None
|
| + 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.iteritems():
|
| + 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 declare(self, name, cname, type, pos, visibility, shadow = 0, is_type = 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:
|
| + if visibility == 'extern':
|
| + warning(pos, "'%s' redeclared " % name, 0)
|
| + elif visibility != 'ignore':
|
| + error(pos, "'%s' redeclared " % name)
|
| + entry = Entry(name, cname, type, pos = pos)
|
| + entry.in_cinclude = self.in_cinclude
|
| + 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:
|
| + 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):
|
| + # 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)
|
| + 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 == 'public' or api):
|
| + cname = name
|
| + else:
|
| + cname = self.mangle(Naming.type_prefix, name)
|
| + try:
|
| + type = PyrexTypes.create_typedef_type(name, base_type, cname,
|
| + (visibility == 'extern'))
|
| + except ValueError, 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)
|
| + 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 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")
|
| + 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")
|
| +
|
| + 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.scope)
|
| + if entry.type.scope:
|
| + declare_inherited_attributes(entry, base_classes)
|
| + entry.type.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):
|
| + if name:
|
| + if not cname:
|
| + if self.in_cinclude or (visibility == 'public' or api):
|
| + cname = name
|
| + else:
|
| + cname = self.mangle(Naming.type_prefix, name)
|
| + type = PyrexTypes.CEnumType(name, cname, typedef_flag)
|
| + else:
|
| + type = PyrexTypes.c_anon_enum_type
|
| + entry = self.declare_type(name, type, pos, cname = cname,
|
| + visibility = visibility, api = api)
|
| + entry.enum_values = []
|
| + self.sue_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 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):
|
| + # 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 visibility != 'private' and visibility != entry.visibility:
|
| + warning(pos, "Function '%s' previously declared as '%s'" % (name, entry.visibility), 1)
|
| + if not entry.type.same_as(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
|
| + 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
|
| + 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
|
| + type.entry = entry
|
| + return entry
|
| +
|
| + def add_cfunction(self, name, type, pos, cname, visibility, 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
|
| + self.cfunc_entries.append(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:
|
| + res = PyrexTypes.best_match(operands[1:], method.all_alternatives())
|
| + if res is not None:
|
| + return res
|
| + function = self.lookup("operator%s" % operator)
|
| + if function is None:
|
| + return None
|
| + return PyrexTypes.best_match(operands, function.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 generate_library_function_declarations(self, code):
|
| + # Generate extern decls for C library funcs used.
|
| + pass
|
| +
|
| + 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
|
| +
|
| + 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):
|
| + self.outer_scope.add_include_file(filename)
|
| +
|
| +
|
| +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 self.builtin_entries.iteritems():
|
| + cname, type = definition
|
| + self.declare_var(name, type, None, cname)
|
| +
|
| + def lookup(self, name, language_level=None):
|
| + # 'language_level' is passed by ModuleScope
|
| + if language_level == 3:
|
| + if name == '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)
|
| +
|
| + 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',
|
| + 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)
|
| + var_entry.is_variable = 1
|
| + var_entry.is_builtin = 1
|
| + var_entry.utility_code = utility_code
|
| + 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 = "((PyObject*)%s)" % entry.type.typeptr_cname)
|
| + 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
|
| + 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
|
| + # python_include_files [string] Standard Python headers to be included
|
| + # include_files [string] Other C headers to be included
|
| + # 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
|
| +
|
| + def __init__(self, name, parent_module, context):
|
| + 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.python_include_files = ["Python.h"]
|
| + self.include_files = []
|
| + 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
|
| + for var_name in ['__builtins__', '__name__', '__file__', '__doc__', '__path__']:
|
| + self.declare_var(EncodedString(var_name), py_object_type, None)
|
| +
|
| + def qualifying_scope(self):
|
| + return self.parent_module
|
| +
|
| + def global_scope(self):
|
| + return self
|
| +
|
| + def lookup(self, name):
|
| + entry = self.lookup_here(name)
|
| + if entry is not None:
|
| + return entry
|
| +
|
| + if self.context is not None:
|
| + language_level = self.context.language_level
|
| + else:
|
| + language_level = 3
|
| +
|
| + return self.outer_scope.lookup(name, language_level=language_level)
|
| +
|
| + 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
|
| + 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
|
| + return entry
|
| +
|
| + def find_module(self, module_name, pos):
|
| + # 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 self.global_scope().context.find_module(
|
| + module_name, relative_to = self.parent_module, pos = pos)
|
| +
|
| + 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.
|
| + scope = self.lookup_submodule(name)
|
| + if not scope:
|
| + scope = ModuleScope(name,
|
| + parent_module = self, context = self.context)
|
| + self.module_entries[name] = scope
|
| + return scope
|
| +
|
| + def lookup_submodule(self, name):
|
| + # Return scope for submodule of this module, or None.
|
| + return self.module_entries.get(name, None)
|
| +
|
| + def add_include_file(self, filename):
|
| + if filename not in self.python_include_files \
|
| + and filename not in self.include_files:
|
| + self.include_files.append(filename)
|
| +
|
| + def add_imported_module(self, scope):
|
| + if scope not in self.cimported_modules:
|
| + for filename in scope.include_files:
|
| + self.add_include_file(filename)
|
| + 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 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.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.is_pyobject:
|
| + entry.init = 0
|
| + 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):
|
| + # 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)
|
| + 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)
|
| + 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 declare_c_class(self, name, pos, defining = 0, implementing = 0,
|
| + module_name = None, base_type = None, objstruct_cname = None,
|
| + typeobj_cname = None, typeptr_cname = None, visibility = 'private', typedef_flag = 0, api = 0,
|
| + 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:
|
| + type = PyrexTypes.PyExtensionType(name, typedef_flag, base_type, visibility == 'extern')
|
| + 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.
|
| + import Builtin
|
| + var_entry = Entry(name = entry.name,
|
| + type = Builtin.type_type,
|
| + pos = entry.pos,
|
| + cname = "((PyObject*)%s)" % entry.type.typeptr_cname)
|
| + var_entry.is_variable = 1
|
| + var_entry.is_cglobal = 1
|
| + var_entry.is_readonly = 1
|
| + 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 type.is_pyobject:
|
| + entry.init = "0"
|
| + 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)
|
| + 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:
|
| + 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):
|
| + for entry in self.entries.values():
|
| + if entry.from_closure:
|
| + cname = entry.outer_entry.cname
|
| + if self.is_passthrough:
|
| + entry.cname = cname
|
| + else:
|
| + if cname.startswith(Naming.cur_scope_cname):
|
| + cname = cname[len(Naming.cur_scope_cname)+2:]
|
| + entry.cname = "%s->%s" % (outer_scope_cname, cname)
|
| + 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).
|
| + """
|
| + def __init__(self, outer_scope):
|
| + name = outer_scope.global_scope().next_id(Naming.genexpr_id_ref)
|
| + Scope.__init__(self, name, outer_scope, outer_scope)
|
| + self.directives = outer_scope.directives
|
| + self.genexp_prefix = "%s%d%s" % (Naming.pyrex_prefix, len(name), name)
|
| +
|
| + 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 = 1
|
| + entry.is_local = 1
|
| + 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 = 0):
|
| + # 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")
|
| + if visibility != 'private':
|
| + error(pos,
|
| + "C struct/union member cannot be declared %s" % visibility)
|
| + return entry
|
| +
|
| + def declare_cfunction(self, name, type, pos,
|
| + cname = None, visibility = 'private', api = 0, in_pxd = 0,
|
| + defining = 0, modifiers = ()): # currently no utility code ...
|
| + 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")
|
| + 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)
|
| + 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_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_pyobject_attrs = False
|
| + has_memoryview_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.
|
| + if self.has_cyclic_pyobject_attrs:
|
| + 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 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 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
|
| + elif type.is_pyobject and 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
|
| + if name == "__weakref__":
|
| + error(pos, "Special attribute __weakref__ cannot be exposed to Python")
|
| + if not type.is_pyobject:
|
| + if (not type.create_to_py_utility_code(self) or
|
| + (visibility=='public' and not
|
| + type.create_from_py_utility_code(self))):
|
| + 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.
|
| + if name in ('__eq__', '__ne__', '__lt__', '__gt__', '__le__', '__ge__'):
|
| + error(pos, "Special method %s must be implemented via __richcmp__" % 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 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,
|
| + cname = None, visibility = 'private', api = 0, in_pxd = 0,
|
| + defining = 0, modifiers = (), utility_code = None):
|
| + 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 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:
|
| + pass
|
| + elif type.compatible_signature_with(entry.type, as_cmethod = 1) and type.nogil == entry.type.nogil:
|
| + entry = self.add_cfunction(name, type, pos, cname, visibility='ignore', modifiers=modifiers)
|
| + defining = 1
|
| + 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" % 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
|
| +
|
| + def add_cfunction(self, name, type, pos, cname, visibility, modifiers):
|
| + # 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)
|
| + 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.is_variable = 1
|
| + var_entry.is_builtin = 1
|
| + var_entry.utility_code = utility_code
|
| + 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)
|
| + 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,
|
| + allow_pyobject = 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:
|
| + if not entry.type.same_as(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:
|
| + entry.func_cname = "%s::%s" % (self.type.declaration_code(""), cname)
|
| + if name != "this" and (defining or name != "<init>"):
|
| + self.var_entries.append(entry)
|
| + if type.is_pyobject and not allow_pyobject:
|
| + error(pos,
|
| + "C++ class member cannot be a Python object")
|
| + return entry
|
| +
|
| + def check_base_default_constructor(self, pos):
|
| + # Look for default constructors in all base classes.
|
| + if self.default_constructor is None:
|
| + entry = self.lookup(self.name)
|
| + if not entry.type.base_classes:
|
| + self.default_constructor = True
|
| + return
|
| + for base_class in entry.type.base_classes:
|
| + if base_class is PyrexTypes.error_type:
|
| + continue
|
| + temp_entry = base_class.scope.lookup_here("<init>")
|
| + found = False
|
| + if temp_entry is None:
|
| + continue
|
| + for alternative in temp_entry.all_alternatives():
|
| + type = alternative.type
|
| + if type.is_ptr:
|
| + type = type.base_type
|
| + if not type.args:
|
| + found = True
|
| + break
|
| + if not found:
|
| + self.default_constructor = temp_entry.scope.name
|
| + error(pos, "no matching function for call to " \
|
| + "%s::%s()" % (temp_entry.scope.name, temp_entry.scope.name))
|
| + elif not self.default_constructor:
|
| + error(pos, "no matching function for call to %s::%s()" %
|
| + (self.default_constructor, self.default_constructor))
|
| +
|
| + def declare_cfunction(self, name, type, pos,
|
| + cname = None, visibility = 'extern', api = 0, in_pxd = 0,
|
| + defining = 0, modifiers = (), utility_code = None):
|
| + if name in (self.name.split('::')[-1], '__init__') and cname is None:
|
| + self.check_base_default_constructor(pos)
|
| + cname = self.type.cname
|
| + name = '<init>'
|
| + type.return_type = PyrexTypes.InvisibleVoidType()
|
| + elif name == '__dealloc__' and cname is None:
|
| + cname = "~%s" % self.type.cname
|
| + name = '<del>'
|
| + type.return_type = PyrexTypes.InvisibleVoidType()
|
| + 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_scope):
|
| + # 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:
|
| + #contructor is not inherited
|
| + if base_entry.name == "<init>":
|
| + 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
|
| + 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, 0,
|
| + modifiers = base_entry.func_modifiers,
|
| + utility_code = base_entry.utility_code)
|
| + entry.is_inherited = 1
|
| +
|
| + def specialize(self, values):
|
| + scope = CppClassScope(self.name, self.outer_scope)
|
| + 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
|
|
|