Symtab.py 63.3 KB
Newer Older
William Stein's avatar
William Stein committed
1
#
2
#   Symbol Table
William Stein's avatar
William Stein committed
3 4 5
#

import re
6
from Cython import Utils
7
from Errors import warning, error, InternalError
8
from StringEncoding import EncodedString
William Stein's avatar
William Stein committed
9 10
import Options
import Naming
11
import PyrexTypes
12
from PyrexTypes import py_object_type
13
import TypeSlots
William Stein's avatar
William Stein committed
14 15 16
from TypeSlots import \
    pyfunction_signature, pymethod_signature, \
    get_special_method_signature, get_property_accessor_signature
17
import ControlFlow
18
import __builtin__
Stefan Behnel's avatar
Stefan Behnel committed
19 20 21 22
try:
    set
except NameError:
    from sets import Set as set
William Stein's avatar
William Stein committed
23

24
possible_identifier = re.compile(ur"(?![0-9])\w+$", re.U).match
25
nice_identifier = re.compile('^[a-zA-Z0-0_]+$').match
William Stein's avatar
William Stein committed
26

27
class BufferAux:
28 29
    writable_needed = False
    
30 31
    def __init__(self, buffer_info_var, stridevars, shapevars,
                 suboffsetvars):
32 33 34
        self.buffer_info_var = buffer_info_var
        self.stridevars = stridevars
        self.shapevars = shapevars
35
        self.suboffsetvars = suboffsetvars
36
        
37 38 39
    def __repr__(self):
        return "<BufferAux %r>" % self.__dict__

William Stein's avatar
William Stein committed
40 41 42 43 44 45 46 47 48
class Entry:
    # 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'
49
    # is_builtin       boolean    Is an entry in the Python builtins dict
William Stein's avatar
William Stein committed
50 51 52 53
    # is_cglobal       boolean    Is a C global variable
    # is_pyglobal      boolean    Is a Python module-level variable
    #                               or class attribute during
    #                               class construction
54
    # is_member        boolean    Is an assigned class member
William Stein's avatar
William Stein committed
55 56 57
    # is_variable      boolean    Is a variable
    # is_cfunction     boolean    Is a C function
    # is_cmethod       boolean    Is a C method of an extension type
58
    # is_unbound_cmethod boolean  Is an unbound C method of an extension type
William Stein's avatar
William Stein committed
59 60 61 62 63 64 65
    # is_type          boolean    Is a type definition
    # 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
66
    # is_arg           boolean    Is the arg of a method
67
    # is_local         boolean    Is a local variable
68
    # in_closure       boolean    Is referenced in an inner scope
William Stein's avatar
William Stein committed
69 70 71 72 73 74 75 76 77
    # is_readonly      boolean    Can't be assigned to
    # func_cname       string     C func implementing Python func
    # 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
    # init_to_none     boolean    True if initial value should be None
    # as_variable      Entry      Alternative interpretation of extension
78
    #                               type name or builtin C function as a variable
William Stein's avatar
William Stein committed
79 80 81 82 83 84 85 86 87 88 89
    # 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
90
    # is_identifier    boolean    For string const entries, value is an identifier
91
    # used             boolean
92 93 94
    # 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)
Stefan Behnel's avatar
Stefan Behnel committed
95
    # api              boolean    Generate C API for C class or function
Stefan Behnel's avatar
Stefan Behnel committed
96
    # utility_code     string     Utility code needed when this entry is used
97 98
    #
    # buffer_aux      BufferAux or None  Extra information needed for buffer variables
William Stein's avatar
William Stein committed
99 100 101 102 103 104 105

    borrowed = 0
    init = ""
    visibility = 'private'
    is_builtin = 0
    is_cglobal = 0
    is_pyglobal = 0
106
    is_member = 0
William Stein's avatar
William Stein committed
107 108 109
    is_variable = 0
    is_cfunction = 0
    is_cmethod = 0
110
    is_unbound_cmethod = 0
William Stein's avatar
William Stein committed
111 112 113 114 115 116 117
    is_type = 0
    is_const = 0
    is_property = 0
    doc_cname = None
    getter_cname = None
    setter_cname = None
    is_self_arg = 0
118
    is_arg = 0
119
    is_local = 0
120
    in_closure = 0
William Stein's avatar
William Stein committed
121 122 123 124 125 126 127 128 129 130 131
    is_declared_generic = 0
    is_readonly = 0
    func_cname = None
    doc = None
    init_to_none = 0
    as_variable = None
    xdecref_cleanup = 0
    in_cinclude = 0
    as_module = None
    is_inherited = 0
    pystring_cname = None
132
    is_identifier = 0
William Stein's avatar
William Stein committed
133
    is_interned = 0
134
    used = 0
135 136 137
    is_special = 0
    defined_in_pxd = 0
    api = 0
Stefan Behnel's avatar
Stefan Behnel committed
138
    utility_code = None
139
    is_overridable = 0
140
    buffer_aux = None
141

William Stein's avatar
William Stein committed
142 143 144 145 146 147
    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
148
        
149 150 151
    def redeclared(self, pos):
        error(pos, "'%s' does not match previous declaration" % self.name)
        error(self.pos, "Previous declaration is here")
152

William Stein's avatar
William Stein committed
153 154 155 156 157
class Scope:
    # 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
158
    # type_entries      [Entry]            Struct/union/enum/typedef/exttype entries
William Stein's avatar
William Stein committed
159 160 161 162 163 164 165 166 167 168
    # 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
    # temp_entries      [Entry]            Temporary variable entries
    # free_temp_entries [Entry]            Temp variables currently unused
    # temp_counter      integer            Counter for naming temp vars
    # cname_to_entry    {string : Entry}   Temp cname to entry mapping
169
    # int_to_entry      {int : Entry}      Temp cname to entry mapping
William Stein's avatar
William Stein committed
170 171 172 173 174 175 176 177 178
    # pow_function_used boolean            The C pow() function is used
    # return_type       PyrexType or None  Return type of function owning scope
    # is_py_class_scope boolean            Is a Python class scope
    # is_c_class_scope  boolean            Is an extension type scope
    # scope_prefix      string             Disambiguator for C names
    # in_cinclude       boolean            Suppress C declaration code
    # qualified_name    string             "modname" or "modname.classname"
    # pystring_entries  [Entry]            String const entries newly used as
    #                                        Python strings in this scope
179
    # control_flow     ControlFlow  Used for keeping track of environment state
180
    # nogil             boolean            In a nogil section
William Stein's avatar
William Stein committed
181 182 183

    is_py_class_scope = 0
    is_c_class_scope = 0
184
    is_module_scope = 0
William Stein's avatar
William Stein committed
185 186
    scope_prefix = ""
    in_cinclude = 0
187
    nogil = 0
William Stein's avatar
William Stein committed
188
    
189 190
    temp_prefix = Naming.pyrex_prefix
    
William Stein's avatar
William Stein committed
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
    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 = name
            self.scope_prefix = mangled_name
        self.entries = {}
        self.const_entries = []
207
        self.type_entries = []
William Stein's avatar
William Stein committed
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
        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.temp_entries = []
        self.free_temp_entries = []
        #self.pending_temp_entries = [] # TEMPORARY
        self.temp_counter = 1
        self.cname_to_entry = {}
        self.pow_function_used = 0
        self.string_to_entry = {}
223
        self.identifier_to_entry = {}
224
        self.num_to_entry = {}
Robert Bradshaw's avatar
Robert Bradshaw committed
225
        self.obj_to_entry = {}
William Stein's avatar
William Stein committed
226
        self.pystring_entries = []
227
        self.buffer_entries = []
228 229 230 231
        self.control_flow = ControlFlow.LinearControlFlow()
        
    def start_branching(self, pos):
        self.control_flow = self.control_flow.start_branch(pos)
William Stein's avatar
William Stein committed
232
    
233 234 235 236 237 238
    def next_branch(self, pos):
        self.control_flow = self.control_flow.next_branch(pos)
        
    def finish_branching(self, pos):
        self.control_flow = self.control_flow.finish_branch(pos)
        
William Stein's avatar
William Stein committed
239 240
    def __str__(self):
        return "<%s %s>" % (self.__class__.__name__, self.qualified_name)
241

242 243
    def intern_identifier(self, name):
        return self.global_scope().intern_identifier(name)
244

William Stein's avatar
William Stein committed
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
    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 global_scope(self):
        # Return the module-level scope containing this scope.
        return self.outer_scope.global_scope()
    
265 266 267 268
    def builtin_scope(self):
        # Return the module-level scope containing this scope.
        return self.outer_scope.builtin_scope()

269
    def declare(self, name, cname, type, pos, visibility):
William Stein's avatar
William Stein committed
270
        # Create new entry, and add to dictionary if
271
        # name is not None. Reports a warning if already 
William Stein's avatar
William Stein committed
272
        # declared.
273
        if not self.in_cinclude and cname and re.match("^_[_A-Z]+$", cname):
274
            # See http://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html#Reserved-Names 
275
            warning(pos, "'%s' is a reserved name in C." % cname, -1)
William Stein's avatar
William Stein committed
276 277
        dict = self.entries
        if name and dict.has_key(name):
278 279 280 281
            if visibility == 'extern':
                warning(pos, "'%s' redeclared " % name, 0)
            else:
                error(pos, "'%s' redeclared " % name)
William Stein's avatar
William Stein committed
282 283 284 285 286
        entry = Entry(name, cname, type, pos = pos)
        entry.in_cinclude = self.in_cinclude
        if name:
            entry.qualified_name = self.qualify_name(name)
            dict[name] = entry
287
        entry.scope = self
288
        entry.visibility = visibility
William Stein's avatar
William Stein committed
289 290 291 292 293
        return entry
    
    def qualify_name(self, name):
        return "%s.%s" % (self.qualified_name, name)
    
Robert Bradshaw's avatar
Robert Bradshaw committed
294
    def declare_const(self, name, type, value, pos, cname = None, visibility = 'private'):
William Stein's avatar
William Stein committed
295 296 297 298 299 300
        # Add an entry for a named constant.
        if not cname:
            if self.in_cinclude:
                cname = name
            else:
                cname = self.mangle(Naming.enum_prefix, name)
Robert Bradshaw's avatar
Robert Bradshaw committed
301
        entry = self.declare(name, cname, type, pos, visibility)
William Stein's avatar
William Stein committed
302 303 304 305 306
        entry.is_const = 1
        entry.value = value
        return entry
    
    def declare_type(self, name, type, pos, 
307
            cname = None, visibility = 'private', defining = 1):
William Stein's avatar
William Stein committed
308 309 310
        # Add an entry for a type definition.
        if not cname:
            cname = name
311
        entry = self.declare(name, cname, type, pos, visibility)
William Stein's avatar
William Stein committed
312
        entry.is_type = 1
313 314
        if defining:
            self.type_entries.append(entry)
William Stein's avatar
William Stein committed
315
        return entry
316 317 318 319 320 321 322 323 324 325 326
    
    def declare_typedef(self, name, base_type, pos, cname = None,
            visibility = 'private'):
        if not cname:
            if self.in_cinclude or visibility == 'public':
                cname = name
            else:
                cname = self.mangle(Naming.type_prefix, name)
        type = PyrexTypes.CTypedefType(cname, base_type)
        entry = self.declare_type(name, type, pos, cname, visibility)
        type.qualified_name = entry.qualified_name
Stefan Behnel's avatar
Stefan Behnel committed
327
        return entry
William Stein's avatar
William Stein committed
328 329
        
    def declare_struct_or_union(self, name, kind, scope, 
330
            typedef_flag, pos, cname = None, visibility = 'private'):
William Stein's avatar
William Stein committed
331 332
        # Add an entry for a struct or union definition.
        if not cname:
333
            if self.in_cinclude or visibility == 'public':
William Stein's avatar
William Stein committed
334 335 336 337 338
                cname = name
            else:
                cname = self.mangle(Naming.type_prefix, name)
        entry = self.lookup_here(name)
        if not entry:
339 340
            type = PyrexTypes.CStructOrUnionType(
                name, kind, scope, typedef_flag, cname)
341 342
            entry = self.declare_type(name, type, pos, cname,
                visibility = visibility, defining = scope is not None)
William Stein's avatar
William Stein committed
343 344
            self.sue_entries.append(entry)
        else:
345 346
            if not (entry.is_type and entry.type.is_struct_or_union
                    and entry.type.kind == kind):
347
                warning(pos, "'%s' redeclared  " % name, 0)
William Stein's avatar
William Stein committed
348
            elif scope and entry.type.scope:
349
                warning(pos, "'%s' already defined  (ignoring second definition)" % name, 0)
William Stein's avatar
William Stein committed
350 351
            else:
                self.check_previous_typedef_flag(entry, typedef_flag, pos)
352
                self.check_previous_visibility(entry, visibility, pos)
William Stein's avatar
William Stein committed
353 354
                if scope:
                    entry.type.scope = scope
355
                    self.type_entries.append(entry)
William Stein's avatar
William Stein committed
356 357 358 359 360
        if not scope and not entry.type.scope:
            self.check_for_illegal_incomplete_ctypedef(typedef_flag, pos)
        return entry
    
    def check_previous_typedef_flag(self, entry, typedef_flag, pos):
Stefan Behnel's avatar
Stefan Behnel committed
361
        if typedef_flag != entry.type.typedef_flag:
William Stein's avatar
William Stein committed
362 363 364
            error(pos, "'%s' previously declared using '%s'" % (
                entry.name, ("cdef", "ctypedef")[entry.type.typedef_flag]))
    
365
    def check_previous_visibility(self, entry, visibility, pos):
Stefan Behnel's avatar
Stefan Behnel committed
366
        if entry.visibility != visibility:
367 368 369 370 371
            error(pos, "'%s' previously declared as '%s'" % (
                entry.name, entry.visibility))
    
    def declare_enum(self, name, pos, cname, typedef_flag,
            visibility = 'private'):
William Stein's avatar
William Stein committed
372 373
        if name:
            if not cname:
374
                if self.in_cinclude or visibility == 'public':
William Stein's avatar
William Stein committed
375 376 377
                    cname = name
                else:
                    cname = self.mangle(Naming.type_prefix, name)
378
            type = PyrexTypes.CEnumType(name, cname, typedef_flag)
William Stein's avatar
William Stein committed
379
        else:
380 381 382
            type = PyrexTypes.c_anon_enum_type
        entry = self.declare_type(name, type, pos, cname = cname,
            visibility = visibility)
William Stein's avatar
William Stein committed
383 384 385 386 387 388 389 390
        entry.enum_values = []
        self.sue_entries.append(entry)
        return entry	
    
    def declare_var(self, name, type, pos, 
            cname = None, visibility = 'private', is_cdef = 0):
        # Add an entry for a variable.
        if not cname:
Stefan Behnel's avatar
Stefan Behnel committed
391
            if visibility != 'private':
William Stein's avatar
William Stein committed
392 393 394
                cname = name
            else:
                cname = self.mangle(Naming.var_prefix, name)
395
        entry = self.declare(name, cname, type, pos, visibility)
William Stein's avatar
William Stein committed
396
        entry.is_variable = 1
397
        self.control_flow.set_state((), (name, 'initalized'), False)
William Stein's avatar
William Stein committed
398 399 400 401 402 403 404
        return entry
        
    def declare_builtin(self, name, pos):
        return self.outer_scope.declare_builtin(name, pos)
    
    def declare_pyfunction(self, name, pos):
        # Add an entry for a Python function.
405
        entry = self.lookup_here(name)
406
        if entry and not entry.type.is_cfunction:
407 408
            # This is legal Python, but for now will produce invalid C.
            error(pos, "'%s' already declared" % name)
409
        entry = self.declare_var(name, py_object_type, pos, visibility='extern')
William Stein's avatar
William Stein committed
410 411 412 413 414 415 416 417
        entry.signature = pyfunction_signature
        self.pyfunc_entries.append(entry)
        return entry
    
    def register_pyfunction(self, entry):
        self.pyfunc_entries.append(entry)
    
    def declare_cfunction(self, name, type, pos, 
418
            cname = None, visibility = 'private', defining = 0, api = 0, in_pxd = 0):
William Stein's avatar
William Stein committed
419
        # Add an entry for a C function.
420 421
        entry = self.lookup_here(name)
        if entry:
Stefan Behnel's avatar
Stefan Behnel committed
422
            if visibility != 'private' and visibility != entry.visibility:
423
                warning(pos, "Function '%s' previously declared as '%s'" % (name, entry.visibility), 1)
424
            if not entry.type.same_as(type):
425 426 427 428 429
                if visibility == 'extern' and entry.visibility == 'extern':
                    warning(pos, "Function signature does not match previous declaration", 1)
                    entry.type = type
                else:
                    error(pos, "Function signature does not match previous declaration")
430 431
        else:
            if not cname:
Stefan Behnel's avatar
Stefan Behnel committed
432
                if api or visibility != 'private':
433 434 435 436 437
                    cname = name
                else:
                    cname = self.mangle(Naming.func_prefix, name)
            entry = self.add_cfunction(name, type, pos, cname, visibility)
            entry.func_cname = cname
Stefan Behnel's avatar
Stefan Behnel committed
438
        if in_pxd and visibility != 'extern':
439 440 441
            entry.defined_in_pxd = 1
        if api:
            entry.api = 1
Stefan Behnel's avatar
Stefan Behnel committed
442
        if not defining and not in_pxd and visibility != 'extern':
Stefan Behnel's avatar
Stefan Behnel committed
443
            error(pos, "Non-extern C function '%s' declared but not defined" % name)
William Stein's avatar
William Stein committed
444 445 446 447
        return entry
    
    def add_cfunction(self, name, type, pos, cname, visibility):
        # Add a C function entry without giving it a func_cname.
448
        entry = self.declare(name, cname, type, pos, visibility)
William Stein's avatar
William Stein committed
449 450 451 452 453 454 455 456 457 458 459 460
        entry.is_cfunction = 1
        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)
    
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
    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" % scope.qualified_name)
                return None
        return scope
        
William Stein's avatar
William Stein committed
476 477 478 479
    def lookup(self, name):
        # Look up name in this scope or an enclosing one.
        # Return None if not found.
        return (self.lookup_here(name)
480 481 482 483 484 485 486 487
            or (self.outer_scope and self.outer_scope.lookup_from_inner(name))
            or None)

    def lookup_from_inner(self, name):
        # Look up name in this scope or an enclosing one.
        # This is only called from enclosing scopes.
        return (self.lookup_here(name)
            or (self.outer_scope and self.outer_scope.lookup_from_inner(name))
William Stein's avatar
William Stein committed
488 489 490 491 492 493 494 495 496 497 498 499 500
            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
501

502
    def add_string_const(self, value, identifier = False):
William Stein's avatar
William Stein committed
503
        # Add an entry for a string constant.
504 505 506 507
        if identifier:
            cname = self.new_string_const_cname(value)
        else:
            cname = self.new_const_cname()
508
        if value.is_unicode:
509
            c_type = PyrexTypes.c_utf8_char_array_type
510 511
            value = value.utf8encode()
        else:
512
            c_type = PyrexTypes.c_char_array_type
513 514
            value = value.byteencode()
        entry = Entry("", cname, c_type, init = value)
515
        entry.used = 1
William Stein's avatar
William Stein committed
516 517
        self.const_entries.append(entry)
        return entry
518

519
    def get_string_const(self, value, identifier = False):
William Stein's avatar
William Stein committed
520 521 522
        # Get entry for string constant. Returns an existing
        # one if possible, otherwise creates a new one.
        genv = self.global_scope()
523 524 525 526 527
        if identifier:
            string_map = genv.identifier_to_entry
        else:
            string_map = genv.string_to_entry
        entry = string_map.get(value)
William Stein's avatar
William Stein committed
528
        if not entry:
529
            entry = self.add_string_const(value, identifier)
530 531
            entry.is_identifier = identifier
            string_map[value] = entry
William Stein's avatar
William Stein committed
532
        return entry
533

534
    def add_py_string(self, entry, identifier = None):
William Stein's avatar
William Stein committed
535 536 537 538
        # If not already done, allocate a C name for a Python version of
        # a string literal, and add it to the list of Python strings to
        # be created at module init time. If the string resembles a
        # Python identifier, it will be interned.
539 540 541
        if entry.pystring_cname:
            return
        value = entry.init
542
        entry.pystring_cname = Naming.py_const_prefix + entry.cname[len(Naming.const_prefix):]
543 544
        self.pystring_entries.append(entry)
        self.global_scope().all_pystring_entries.append(entry)
545
        if identifier or (identifier is None and possible_identifier(value)):
546 547
            entry.is_interned = 1
            self.global_scope().new_interned_string_entries.append(entry)
548

549 550 551 552
    def add_py_num(self, value):
        # Add an entry for an int constant.
        cname = "%s%s" % (Naming.interned_num_prefix, value)
        cname = cname.replace('-', 'neg_').replace('.','_')
553
        entry = Entry("", cname, py_object_type, init = value)
554 555 556 557 558 559
        entry.used = 1
        entry.is_interned = 1
        self.const_entries.append(entry)
        self.interned_nums.append(entry)
        return entry
        
560
    def get_py_num(self, value, longness):
561 562
        # Get entry for int constant. Returns an existing
        # one if possible, otherwise creates a new one.
563 564
        if longness or Utils.long_literal(value):
            value += "L"
565 566 567 568 569 570 571
        genv = self.global_scope()
        entry = genv.num_to_entry.get(value)
        if not entry:
            entry = genv.add_py_num(value)
            genv.num_to_entry[value] = entry
            genv.pynum_entries.append(entry)
        return entry
Robert Bradshaw's avatar
Robert Bradshaw committed
572 573 574 575 576 577 578 579 580 581
        
    def get_py_obj(self, obj, c_prefix=''):
        # Get entry for a generic constant. Returns an existing
        # one if possible, otherwise creates a new one.
        genv = self.global_scope()
        entry = genv.obj_to_entry.get(obj)
        if not entry:
            entry = genv.add_py_num(obj, c_prefix)
            genv.obj_to_entry[obj] = entry
        return entry
William Stein's avatar
William Stein committed
582
    
583 584 585 586 587 588 589
    def new_string_const_cname(self, value):
        # Create a new globally-unique nice name for a string constant.
        if len(value) < 20 and nice_identifier(value):
            return "%s%s" % (Naming.const_prefix, value)
        else:
            return self.global_scope().new_const_cname()

William Stein's avatar
William Stein committed
590 591 592 593 594 595 596 597 598 599 600 601 602 603
    def new_const_cname(self):
        # Create a new globally-unique name for a constant.
        return self.global_scope().new_const_cname()

    def allocate_temp(self, type):
        # Allocate a temporary variable of the given type from the 
        # free list if available, otherwise create a new one.
        # Returns the cname of the variable.
        for entry in self.free_temp_entries:
            if entry.type == type:
                self.free_temp_entries.remove(entry)
                return entry.cname
        n = self.temp_counter
        self.temp_counter = n + 1
604
        cname = "%s%d" % (self.temp_prefix, n)
William Stein's avatar
William Stein committed
605
        entry = Entry("", cname, type)
606
        entry.used = 1
607
        if type.is_pyobject or type == PyrexTypes.c_py_ssize_t_type:
William Stein's avatar
William Stein committed
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631
            entry.init = "0"
        self.cname_to_entry[entry.cname] = entry
        self.temp_entries.append(entry)
        return entry.cname
    
    def allocate_temp_pyobject(self):
        # Allocate a temporary PyObject variable.
        return self.allocate_temp(py_object_type)

    def release_temp(self, cname):
        # Release a temporary variable for re-use.
        if not cname: # can happen when type of an expr is void
            return
        entry = self.cname_to_entry[cname]
        if entry in self.free_temp_entries:
            raise InternalError("Temporary variable %s released more than once"
                % cname)
        self.free_temp_entries.append(entry)
    
    def temps_in_use(self):
        # Return a new list of temp entries currently in use.
        return [entry for entry in self.temp_entries
            if entry not in self.free_temp_entries]
    
632 633 634
    def use_utility_code(self, new_code, name=None):
        self.global_scope().use_utility_code(new_code, name)

William Stein's avatar
William Stein committed
635 636 637 638 639 640 641 642 643 644 645 646 647 648
    def generate_library_function_declarations(self, code):
        # Generate extern decls for C library funcs used.
        #if self.pow_function_used:
        #	code.putln("%s double pow(double, double);" % Naming.extern_c_macro)
        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

649
class PreImportScope(Scope):
650 651 652

    namespace_cname = Naming.preimport_cname

653 654 655 656
    def __init__(self):
        Scope.__init__(self, Options.pre_import, None, None)
        
    def declare_builtin(self, name, pos):
657
        entry = self.declare(name, name, py_object_type, pos, 'private')
658 659 660 661
        entry.is_variable = True
        entry.is_pyglobal = True
        return entry

William Stein's avatar
William Stein committed
662 663 664 665 666

class BuiltinScope(Scope):
    #  The builtin namespace.
    
    def __init__(self):
667 668 669 670
        if Options.pre_import is None:
            Scope.__init__(self, "__builtin__", None, None)
        else:
            Scope.__init__(self, "__builtin__", PreImportScope(), None)
Robert Bradshaw's avatar
Robert Bradshaw committed
671
        self.type_names = {}
672
        
Robert Bradshaw's avatar
Robert Bradshaw committed
673 674 675
        for name, definition in self.builtin_entries.iteritems():
            cname, type = definition
            self.declare_var(name, type, None, cname)
676
        
William Stein's avatar
William Stein committed
677
    def declare_builtin(self, name, pos):
678
        if not hasattr(__builtin__, name):
679 680 681 682
            if self.outer_scope is not None:
                return self.outer_scope.declare_builtin(name, pos)
            else:
                error(pos, "undeclared name not builtin: %s"%name)
Stefan Behnel's avatar
Stefan Behnel committed
683 684 685 686 687
    
    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.
688
        name = EncodedString(name)
689
        entry = self.declare_cfunction(name, type, None, cname)
Stefan Behnel's avatar
Stefan Behnel committed
690 691 692 693
        entry.utility_code = utility_code
        if python_equiv:
            if python_equiv == "*":
                python_equiv = name
694
            else:
695
                python_equiv = EncodedString(python_equiv)
Stefan Behnel's avatar
Stefan Behnel committed
696
            var_entry = Entry(python_equiv, python_equiv, py_object_type)
697 698 699 700
            var_entry.is_variable = 1
            var_entry.is_builtin = 1
            entry.as_variable = var_entry
        return entry
Robert Bradshaw's avatar
Robert Bradshaw committed
701 702
        
    def declare_builtin_type(self, name, cname):
703
        name = EncodedString(name)
Robert Bradshaw's avatar
Robert Bradshaw committed
704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
        type = PyrexTypes.BuiltinObjectType(name, cname)
        type.set_scope(CClassScope(name, outer_scope=None, visibility='extern'))
        self.type_names[name] = 1
        entry = self.declare_type(name, type, None, visibility='extern')

        var_entry = Entry(name = entry.name,
            type = py_object_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

        return type
719

720 721 722
    def builtin_scope(self):
        return self
        
Robert Bradshaw's avatar
Robert Bradshaw committed
723
    builtin_entries = {
724 725 726
        "int":    ["((PyObject*)&PyInt_Type)", py_object_type],
        "long":   ["((PyObject*)&PyLong_Type)", py_object_type],
        "float":  ["((PyObject*)&PyFloat_Type)", py_object_type],
Robert Bradshaw's avatar
Robert Bradshaw committed
727
        
728
        "str":    ["((PyObject*)&PyBytes_Type)", py_object_type],
729
        "unicode":["((PyObject*)&PyUnicode_Type)", py_object_type],
730 731 732 733 734
        "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],
Robert Bradshaw's avatar
Robert Bradshaw committed
735
        
736 737 738
        "type":   ["((PyObject*)&PyType_Type)", py_object_type],
        "slice":  ["((PyObject*)&PySlice_Type)", py_object_type],
        "file":   ["((PyObject*)&PyFile_Type)", py_object_type],
739

Robert Bradshaw's avatar
Robert Bradshaw committed
740 741 742 743
        "None":   ["Py_None", py_object_type],
        "False":  ["Py_False", py_object_type],
        "True":   ["Py_True", py_object_type],
    }
William Stein's avatar
William Stein committed
744

745 746
const_counter = 1 # As a temporary solution for compiling code in pxds

William Stein's avatar
William Stein committed
747 748 749 750 751 752 753
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
754
    # const_counter        integer            Counter for naming constants (PS: MOVED TO GLOBAL)
755
    # utility_code_list    [((string, string), string)] Queuing utility codes for forwarding to Code.py
William Stein's avatar
William Stein committed
756 757 758 759
    # default_entries      [Entry]            Function argument default entries
    # 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
760
    # identifier_to_entry  {string : Entry}   Map identifier string const to entry
William Stein's avatar
William Stein committed
761 762 763 764
    # 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)
765
    # included_files       [string]           Cython sources included with 'include'
William Stein's avatar
William Stein committed
766 767
    # pxd_file_loaded      boolean            Corresponding .pxd file has been processed
    # cimported_modules    [ModuleScope]      Modules imported with cimport
768
    # new_interned_string_entries [Entry]     New interned strings waiting to be declared
769
    # interned_nums        [int/long]         Interned numeric constants
William Stein's avatar
William Stein committed
770
    # all_pystring_entries [Entry]            Python string consts from all scopes
771
    # types_imported       {PyrexType : 1}    Set of types for which import code generated
772
    # has_import_star      boolean            Module contains import *
773 774
    
    is_module_scope = 1
775
    has_import_star = 0
William Stein's avatar
William Stein committed
776 777 778 779 780 781 782 783 784 785 786 787

    def __init__(self, name, parent_module, context):
        self.parent_module = parent_module
        outer_scope = context.find_submodule("__builtin__")
        Scope.__init__(self, name, outer_scope, parent_module)
        self.module_name = 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
788
        self.utility_code_list = []
William Stein's avatar
William Stein committed
789 790 791 792
        self.default_entries = []
        self.module_entries = {}
        self.python_include_files = ["Python.h", "structmember.h"]
        self.include_files = []
Robert Bradshaw's avatar
Robert Bradshaw committed
793
        self.type_names = dict(outer_scope.type_names)
William Stein's avatar
William Stein committed
794 795
        self.pxd_file_loaded = 0
        self.cimported_modules = []
796
        self.new_interned_string_entries = []
797
        self.interned_nums = []
Robert Bradshaw's avatar
Robert Bradshaw committed
798
        self.interned_objs = []
William Stein's avatar
William Stein committed
799
        self.all_pystring_entries = []
800
        self.types_imported = {}
801
        self.included_files = []
802
        self.pynum_entries = []
803
        self.has_extern_class = 0
804 805
        self.cached_builtins = []
        self.undeclared_cached_builtins = []
806
        self.namespace_cname = self.module_cname
William Stein's avatar
William Stein committed
807 808 809 810 811 812 813 814
    
    def qualifying_scope(self):
        return self.parent_module
    
    def global_scope(self):
        return self
    
    def declare_builtin(self, name, pos):
815
        if not hasattr(__builtin__, name):
816 817 818 819
            if self.has_import_star:
                entry = self.declare_var(name, py_object_type, pos)
                return entry
            elif self.outer_scope is not None:
820 821 822
                return self.outer_scope.declare_builtin(name, pos)
            else:
                error(pos, "undeclared name not builtin: %s"%name)
823 824 825 826
        if Options.cache_builtins:
            for entry in self.cached_builtins:
                if entry.name == name:
                    return entry
827
        entry = self.declare(None, None, py_object_type, pos, 'private')
828 829 830
        if Options.cache_builtins:
            entry.is_builtin = 1
            entry.is_const = 1
831
            entry.name = name
832 833 834 835 836
            entry.cname = Naming.builtin_prefix + name
            self.cached_builtins.append(entry)
            self.undeclared_cached_builtins.append(entry)
        else:
            entry.is_builtin = 1
William Stein's avatar
William Stein committed
837
        return entry
838

839 840
    def intern_identifier(self, name):
        string_entry = self.get_string_const(name, identifier = True)
841
        self.add_py_string(string_entry, identifier = 1)
842
        return string_entry.pystring_cname
William Stein's avatar
William Stein committed
843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878

    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:
            self.cimported_modules.append(scope)
    
    def add_imported_entry(self, name, entry, pos):
        if entry not in self.entries:
            self.entries[name] = entry
        else:
879
            warning(pos, "'%s' redeclared  " % name, 0)
William Stein's avatar
William Stein committed
880 881 882 883 884 885 886 887
    
    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:
888 889
            if entry.is_pyglobal and entry.as_module is scope:
                return entry # Already declared as the same module
William Stein's avatar
William Stein committed
890
            if not (entry.is_pyglobal and not entry.as_module):
891 892 893 894 895 896 897 898
                # 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
899
                warning(pos, "'%s' redeclared  " % name, 0)
William Stein's avatar
William Stein committed
900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939
                return None
        else:
            entry = self.declare_var(name, py_object_type, pos)
        entry.as_module = scope
        self.cimported_modules.append(scope)
        return entry
    
    def declare_var(self, name, type, pos, 
            cname = None, visibility = 'private', 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.
        entry = Scope.declare_var(self, name, type, pos, 
            cname, visibility, is_cdef)
        if not visibility in ('private', 'public', 'extern'):
            error(pos, "Module-level variable cannot be declared %s" % visibility)
        if not is_cdef:
            if not (type.is_pyobject and not type.is_extension_type):
                raise InternalError(
                    "Non-cdef global variable is not a generic Python object")
            entry.is_pyglobal = 1
        else:
            entry.is_cglobal = 1
            self.var_entries.append(entry)
        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 add_default_value(self, type):
        # Add an entry for holding a function argument
        # default value.
        cname = self.new_const_cname()
        entry = Entry("", cname, type)
        self.default_entries.append(entry)
        return entry
        
940
    def new_const_cname(self):
941
        global const_counter
William Stein's avatar
William Stein committed
942
        # Create a new globally-unique name for a constant.
943
        prefix=''
944 945
        n = const_counter
        const_counter = n + 1
946
        return "%s%s%d" % (Naming.const_prefix, prefix, n)
William Stein's avatar
William Stein committed
947
    
948
    def use_utility_code(self, new_code, name=None):
949 950
        self.utility_code_list.append((new_code, name))

951 952
    def declare_c_class(self, name, pos, defining = 0, implementing = 0,
        module_name = None, base_type = None, objstruct_cname = None,
953 954
        typeobj_cname = None, visibility = 'private', typedef_flag = 0, api = 0,
        buffer_defaults = None):
William Stein's avatar
William Stein committed
955
        #
956
        #  Look for previous declaration as a type
William Stein's avatar
William Stein committed
957 958 959 960 961
        #
        entry = self.lookup_here(name)
        if entry:
            type = entry.type
            if not (entry.is_type and type.is_extension_type):
962
                entry = None # Will cause redeclaration and produce an error
William Stein's avatar
William Stein committed
963
            else:
964
                scope = type.scope
Robert Bradshaw's avatar
Robert Bradshaw committed
965
                if typedef_flag and (not scope or scope.defined):
966 967 968 969 970 971
                    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
William Stein's avatar
William Stein committed
972
        #
973
        #  Make a new entry if needed
William Stein's avatar
William Stein committed
974 975
        #
        if not entry:
976
            type = PyrexTypes.PyExtensionType(name, typedef_flag, base_type)
977
            type.pos = pos
978
            type.buffer_defaults = buffer_defaults
William Stein's avatar
William Stein committed
979 980 981 982 983
            if visibility == 'extern':
                type.module_name = module_name
            else:
                type.module_name = self.qualified_name
            type.typeptr_cname = self.mangle(Naming.typeptr_prefix, name)
984 985
            entry = self.declare_type(name, type, pos, visibility = visibility,
                defining = 0)
William Stein's avatar
William Stein committed
986 987 988 989 990 991 992 993 994 995
            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)
        #
996
        #  Check for re-definition and create scope if needed
William Stein's avatar
William Stein committed
997 998 999 1000 1001 1002 1003 1004
        #
        if not type.scope:
            if defining or implementing:
                scope = CClassScope(name = name, outer_scope = self,
                    visibility = visibility)
                if base_type:
                    scope.declare_inherited_c_attributes(base_type.scope)
                type.set_scope(scope)
1005
                self.type_entries.append(entry)
William Stein's avatar
William Stein committed
1006 1007 1008 1009 1010 1011 1012 1013
            else:
                self.check_for_illegal_incomplete_ctypedef(typedef_flag, pos)
        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)
        #
1014
        #  Fill in options, checking for compatibility with any previous declaration
William Stein's avatar
William Stein committed
1015
        #
1016 1017
        if defining:
            entry.defined_in_pxd = 1
William Stein's avatar
William Stein committed
1018 1019
        if implementing:   # So that filenames in runtime exceptions refer to
            entry.pos = pos  # the .pyx file and not the .pxd file
Stefan Behnel's avatar
Stefan Behnel committed
1020
        if visibility != 'private' and entry.visibility != visibility:
Stefan Behnel's avatar
Stefan Behnel committed
1021 1022 1023 1024
            error(pos, "Class '%s' previously declared as '%s'"
                % (name, entry.visibility))
        if api:
            entry.api = 1
William Stein's avatar
William Stein committed
1025
        if objstruct_cname:
Stefan Behnel's avatar
Stefan Behnel committed
1026
            if type.objstruct_cname and type.objstruct_cname != objstruct_cname:
William Stein's avatar
William Stein committed
1027 1028 1029
                error(pos, "Object struct name differs from previous declaration")
            type.objstruct_cname = objstruct_cname		
        if typeobj_cname:
Stefan Behnel's avatar
Stefan Behnel committed
1030
            if type.typeobj_cname and type.typeobj_cname != typeobj_cname:
William Stein's avatar
William Stein committed
1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
                    error(pos, "Type object name differs from previous declaration")
            type.typeobj_cname = typeobj_cname
        #
        # Return new or existing entry	
        #
        return entry
    
    def check_for_illegal_incomplete_ctypedef(self, typedef_flag, pos):
        if typedef_flag and not self.in_cinclude:
            error(pos, "Forward-referenced type must use 'cdef', not 'ctypedef'")
    
    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:
            #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(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:
Stefan Behnel's avatar
Stefan Behnel committed
1074
            print("Scope.check_c_classes: checking scope " + self.qualified_name)
William Stein's avatar
William Stein committed
1075 1076
        for entry in self.c_class_entries:
            if debug_check_c_classes:
Stefan Behnel's avatar
Stefan Behnel committed
1077 1078 1079
                print("...entry %s %s" % (entry.name, entry))
                print("......type = " + entry.type)
                print("......visibility = " + entry.visibility)
William Stein's avatar
William Stein committed
1080 1081 1082 1083 1084 1085 1086
            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
Stefan Behnel's avatar
Stefan Behnel committed
1087
            if visibility != 'extern' and not type.typeobj_cname:
William Stein's avatar
William Stein committed
1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117
                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 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.
        var_entry = Entry(name = entry.name,
            type = py_object_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
        
1118
class LocalScope(Scope):    
William Stein's avatar
William Stein committed
1119 1120 1121 1122 1123

    def __init__(self, name, outer_scope):
        Scope.__init__(self, name, outer_scope, outer_scope)
    
    def mangle(self, prefix, name):
1124
        return prefix + name
William Stein's avatar
William Stein committed
1125 1126 1127 1128

    def declare_arg(self, name, type, pos):
        # Add an entry for an argument of a function.
        cname = self.mangle(Naming.var_prefix, name)
1129
        entry = self.declare(name, cname, type, pos, 'private')
William Stein's avatar
William Stein committed
1130 1131 1132
        entry.is_variable = 1
        if type.is_pyobject:
            entry.init = "0"
1133
        entry.is_arg = 1
William Stein's avatar
William Stein committed
1134 1135
        #entry.borrowed = 1 # Not using borrowed arg refs for now
        self.arg_entries.append(entry)
Robert Bradshaw's avatar
Robert Bradshaw committed
1136
        self.control_flow.set_state((), (name, 'source'), 'arg')
William Stein's avatar
William Stein committed
1137 1138 1139 1140 1141 1142 1143 1144 1145
        return entry
    
    def declare_var(self, name, type, pos, 
            cname = None, visibility = 'private', 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, visibility, is_cdef)
Robert Bradshaw's avatar
Robert Bradshaw committed
1146 1147 1148
        if type.is_pyobject and not Options.init_local_none:
            entry.init = "0"
        entry.init_to_none = type.is_pyobject and Options.init_local_none
1149
        entry.is_local = 1
William Stein's avatar
William Stein committed
1150 1151 1152 1153 1154 1155
        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):
1156
            warning(pos, "'%s' redeclared  ", 0)
William Stein's avatar
William Stein committed
1157 1158 1159 1160
        else:
            entry = self.global_scope().lookup_target(name)
            self.entries[name] = entry
        
1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175
    def lookup_from_inner(self, name):
        entry = self.lookup_here(name)
        if entry:
            entry.in_closure = 1
            return entry
        else:
            return (self.outer_scope and self.outer_scope.lookup_from_inner(name)) or None
            
    def mangle_closure_cnames(self, scope_var):
        for entry in self.entries.values():
            if entry.in_closure:
                if not hasattr(entry, 'orig_cname'):
                    entry.orig_cname = entry.cname
                entry.cname = scope_var + "->" + entry.cname
                
William Stein's avatar
William Stein committed
1176

1177 1178 1179
class GeneratorLocalScope(LocalScope):

    temp_prefix = Naming.cur_scope_cname + "->" + LocalScope.temp_prefix
1180
    
1181 1182 1183 1184 1185 1186 1187
    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" % (Naming.scope_obj_cname, name)
1188

William Stein's avatar
William Stein committed
1189 1190 1191
class StructOrUnionScope(Scope):
    #  Namespace of a C struct or union.

1192 1193
    def __init__(self, name="?"):
        Scope.__init__(self, name, None, None)
William Stein's avatar
William Stein committed
1194 1195

    def declare_var(self, name, type, pos, 
1196
            cname = None, visibility = 'private', is_cdef = 0, allow_pyobject = 0):
William Stein's avatar
William Stein committed
1197 1198 1199
        # Add an entry for an attribute.
        if not cname:
            cname = name
1200
        if type.is_cfunction:
1201
            type = PyrexTypes.CPtrType(type)
1202
        entry = self.declare(name, cname, type, pos, visibility)
William Stein's avatar
William Stein committed
1203 1204
        entry.is_variable = 1
        self.var_entries.append(entry)
1205
        if type.is_pyobject and not allow_pyobject:
William Stein's avatar
William Stein committed
1206 1207
            error(pos,
                "C struct/union member cannot be a Python object")
Stefan Behnel's avatar
Stefan Behnel committed
1208
        if visibility != 'private':
William Stein's avatar
William Stein committed
1209 1210 1211 1212
            error(pos,
                "C struct/union member cannot be declared %s" % visibility)
        return entry

1213 1214 1215
    def declare_cfunction(self, name, type, pos, 
            cname = None, visibility = 'private', defining = 0, api = 0, in_pxd = 0):
        self.declare_var(name, type, pos, cname, visibility)
William Stein's avatar
William Stein committed
1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230

class ClassScope(Scope):
    #  Abstract base class for namespace of
    #  Python class or extension type.
    #
    #  class_name     string   Pyrex 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

1231 1232
    def add_string_const(self, value, identifier = False):
        return self.outer_scope.add_string_const(value, identifier)
1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250

    def lookup(self, name):
        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 memebers 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. 
            self.use_utility_code(classmethod_utility_code)
            entry = Entry(
                "classmethod", 
                "__Pyx_Method_ClassMethod", 
                PyrexTypes.CFuncType(
                    py_object_type,
                    [PyrexTypes.CFuncTypeArg("", py_object_type, None)], 0, 0))
            entry.is_cfunction = 1
            return entry
        else:
            return Scope.lookup(self, name)
1251
    
William Stein's avatar
William Stein committed
1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301

class PyClassScope(ClassScope):
    #  Namespace of a Python class.
    #
    #  class_dict_cname    string   C variable holding class dict
    #  class_obj_cname     string   C variable holding class object

    is_py_class_scope = 1
    
    def declare_var(self, name, type, pos, 
            cname = None, visibility = 'private', is_cdef = 0):
        # Add an entry for a class attribute.
        entry = Scope.declare_var(self, name, type, pos, 
            cname, visibility, is_cdef)
        entry.is_pyglobal = 1
        return entry

    def allocate_temp(self, type):
        return self.outer_scope.allocate_temp(type)

    def release_temp(self, cname):
        self.outer_scope.release_temp(cname)

    #def recycle_pending_temps(self):
    #	self.outer_scope.recycle_pending_temps()

    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
    #  member_table_cname    string
    #  getset_table_cname    string
    #  has_pyobject_attrs    boolean  Any PyObject attributes?
    #  public_attr_entries   boolean  public/readonly attrs
    #  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
    
    def __init__(self, name, outer_scope, visibility):
        ClassScope.__init__(self, name, outer_scope)
Stefan Behnel's avatar
Stefan Behnel committed
1302
        if visibility != 'extern':
William Stein's avatar
William Stein committed
1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321
            self.method_table_cname = outer_scope.mangle(Naming.methtab_prefix, name)
            self.member_table_cname = outer_scope.mangle(Naming.memtab_prefix, name)
            self.getset_table_cname = outer_scope.mangle(Naming.gstab_prefix, name)
        self.has_pyobject_attrs = 0
        self.public_attr_entries = []
        self.property_entries = []
        self.inherited_var_entries = []
        self.defined = 0
        self.implemented = 0
    
    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.
        return self.has_pyobject_attrs or \
            (self.parent_type.base_type and \
                self.parent_type.base_type.scope.needs_gc())

    def declare_var(self, name, type, pos, 
            cname = None, visibility = 'private', is_cdef = 0):
1322 1323 1324
        if is_cdef:
            # Add an entry for an attribute.
            if self.defined:
William Stein's avatar
William Stein committed
1325
                error(pos,
1326 1327 1328 1329 1330 1331 1332 1333
                    "C attributes cannot be added in implementation part of"
                    " extension type")
            if get_special_method_signature(name):
                error(pos, 
                    "The name '%s' is reserved for a special method."
                        % name)
            if not cname:
                cname = name
1334
            entry = self.declare(name, cname, type, pos, visibility)
1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357
            entry.is_variable = 1
            self.var_entries.append(entry)
            if type.is_pyobject:
                self.has_pyobject_attrs = 1
            if visibility not in ('private', 'public', 'readonly'):
                error(pos,
                    "Attribute of extension type cannot be declared %s" % visibility)
            if visibility in ('public', 'readonly'):
                if type.pymemberdef_typecode:
                    self.public_attr_entries.append(entry)
                    if name == "__weakref__":
                        error(pos, "Special attribute __weakref__ cannot be exposed to Python")
                else:
                    error(pos,
                        "C attribute of type '%s' cannot be accessed from Python" % type)
            if visibility == 'public' and type.is_extension_type:
                error(pos,
                    "Non-generic Python attribute cannot be exposed for writing from Python")
            return entry
        else:
            # Add an entry for a class attribute.
            entry = Scope.declare_var(self, name, type, pos, 
                cname, visibility, is_cdef)
1358 1359 1360 1361
            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
1362
            self.namespace_cname = "(PyObject *)%s" % self.parent_type.typeptr_cname
1363
            entry.interned_cname = self.intern_identifier(name)
1364
            return entry
1365

William Stein's avatar
William Stein committed
1366 1367 1368

    def declare_pyfunction(self, name, pos):
        # Add an entry for a method.
1369
        if name in ('__eq__', '__ne__', '__lt__', '__gt__', '__le__', '__ge__'):
Robert Bradshaw's avatar
Robert Bradshaw committed
1370
            error(pos, "Special method %s must be implemented via __richcmp__" % name)
1371 1372 1373
        if name == "__new__":
            warning(pos, "__new__ method of extension type will change semantics "
                "in a future version of Pyrex and Cython. Use __cinit__ instead.")
1374
            name = EncodedString("__cinit__")
1375
        entry = self.declare_var(name, py_object_type, pos, visibility='extern')
William Stein's avatar
William Stein committed
1376 1377
        special_sig = get_special_method_signature(name)
        if special_sig:
1378 1379
            # Special methods get put in the method table with a particular
            # signature declared in advance.
William Stein's avatar
William Stein committed
1380
            entry.signature = special_sig
1381
            entry.is_special = 1
William Stein's avatar
William Stein committed
1382 1383
        else:
            entry.signature = pymethod_signature
1384
            entry.is_special = 0
1385 1386

        self.pyfunc_entries.append(entry)
William Stein's avatar
William Stein committed
1387
        return entry
1388 1389 1390
    
    def lookup_here(self, name):
        if name == "__new__":
1391
            name = EncodedString("__cinit__")
1392 1393
        return ClassScope.lookup_here(self, name)
    
William Stein's avatar
William Stein committed
1394
    def declare_cfunction(self, name, type, pos,
1395
            cname = None, visibility = 'private', defining = 0, api = 0, in_pxd = 0):
William Stein's avatar
William Stein committed
1396 1397 1398 1399 1400 1401 1402 1403 1404 1405
        if get_special_method_signature(name):
            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 args[0].type.same_as(self.parent_type):
            error(pos, "Self argument of C method does not match parent type")
        entry = self.lookup_here(name)
        if entry:
            if not entry.is_cfunction:
1406
                warning(pos, "'%s' redeclared  " % name, 0)
William Stein's avatar
William Stein committed
1407 1408 1409
            else:
                if defining and entry.func_cname:
                    error(pos, "'%s' already defined" % name)
1410
                #print "CClassScope.declare_cfunction: checking signature" ###
1411
                if type.same_c_signature_as(entry.type, as_cmethod = 1) and type.nogil == entry.type.nogil:
1412
                    pass
1413
                elif type.compatible_signature_with(entry.type, as_cmethod = 1) and type.nogil == entry.type.nogil:
1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426
                    if type.optional_arg_count and not type.original_sig.optional_arg_count:
                        # Need to put a wrapper taking no optional arguments 
                        # into the method table.
                        wrapper_func_cname = self.mangle(Naming.func_prefix, name) + Naming.no_opt_args
                        wrapper_func_name = name + Naming.no_opt_args
                        if entry.type.optional_arg_count:
                            old_entry = self.lookup_here(wrapper_func_name)
                            old_entry.func_cname = wrapper_func_cname
                        else:
                            entry.func_cname = wrapper_func_cname
                            entry.name = wrapper_func_name
                            entry = self.add_cfunction(name, type, pos, cname or name, visibility)
                            defining = 1
1427
                    entry.type = type
1428 1429
#                if type.narrower_c_signature_than(entry.type, as_cmethod = 1):
#                    entry.type = type
1430 1431
                else:
                    error(pos, "Signature not compatible with previous declaration")
1432
                    error(entry.pos, "Previous declaration is here")
William Stein's avatar
William Stein committed
1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449
        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 or name, visibility)
        if defining:
            entry.func_cname = self.mangle(Naming.func_prefix, name)
        return entry
        
    def add_cfunction(self, name, type, pos, cname, visibility):
        # Add a cfunction entry without giving it a func_cname.
        entry = ClassScope.add_cfunction(self, name, type, pos, cname, visibility)
        entry.is_cmethod = 1
        return entry
    
    def declare_property(self, name, doc, pos):
1450 1451
        entry = self.lookup_here(name)
        if entry is None:
1452
            entry = self.declare(name, name, py_object_type, pos, 'private')
William Stein's avatar
William Stein committed
1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469
        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)
        for base_entry in \
            base_scope.inherited_var_entries + base_scope.var_entries:
                entry = self.declare(base_entry.name, adapt(base_entry.cname), 
1470
                    base_entry.type, None, 'private')
William Stein's avatar
William Stein committed
1471 1472 1473
                entry.is_variable = 1
                self.inherited_var_entries.append(entry)
        for base_entry in base_scope.cfunc_entries:
1474 1475
            entry = self.add_cfunction(base_entry.name, base_entry.type,
                    base_entry.pos, adapt(base_entry.cname), base_entry.visibility)
William Stein's avatar
William Stein committed
1476
            entry.is_inherited = 1
Robert Bradshaw's avatar
Robert Bradshaw committed
1477
            
1478 1479
    def allocate_temp(self, type):
        return Scope.allocate_temp(self.global_scope(), type)
William Stein's avatar
William Stein committed
1480

1481 1482 1483 1484
    def release_temp(self, cname):
        return Scope.release_temp(self.global_scope(), cname)
        
        
William Stein's avatar
William Stein committed
1485 1486 1487 1488 1489 1490 1491 1492 1493 1494
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
    
    def declare_pyfunction(self, name, pos):
        # Add an entry for a method.
        signature = get_property_accessor_signature(name)
        if signature:
1495
            entry = self.declare(name, name, py_object_type, pos, 'private')
Stefan Behnel's avatar
Stefan Behnel committed
1496
            entry.is_special = 1
1497
            entry.signature = signature
William Stein's avatar
William Stein committed
1498 1499 1500 1501 1502
            return entry
        else:
            error(pos, "Only __get__, __set__ and __del__ methods allowed "
                "in a property declaration")
            return None
1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522


# Should this go elsewhere (and then get imported)?
#------------------------------------------------------------------------------------

classmethod_utility_code = [
"""
#include "descrobject.h"
static PyObject* __Pyx_Method_ClassMethod(PyObject *method); /*proto*/
""","""
static PyObject* __Pyx_Method_ClassMethod(PyObject *method) {
    /* It appears that PyMethodDescr_Type is not anywhere exposed in the Python/C API */
    /* if (!PyObject_TypeCheck(method, &PyMethodDescr_Type)) { */ 
    if (strcmp(Py_TYPE(method)->tp_name, "method_descriptor") == 0) { /* cdef classes */
        PyMethodDescrObject *descr = (PyMethodDescrObject *)method;
        return PyDescr_NewClassMethod(descr->d_type, descr->d_method);
    }
    else if (PyMethod_Check(method)) {                                /* python classes */
        return PyClassMethod_New(PyMethod_GET_FUNCTION(method));
    }
1523 1524 1525
    else if (PyCFunction_Check(method)) {
        return PyClassMethod_New(method);
    }
1526 1527 1528 1529 1530
    PyErr_Format(PyExc_TypeError, "Class-level classmethod() can only be called on a method_descriptor or instance method.");
    return NULL;
}
"""
]