Cython has moved to github.

cython-devel

view Cython/Compiler/Symtab.py @ 1187:897597836a72

[Cython] PATCH: population of builtin types for 'isinstance' optimization
author "Lisandro Dalcin" <dalcinl@gmail.com>
date Tue Sep 30 11:14:06 2008 -0700 (3 years ago)
parents 515f94dc16f2
children b8802e1bebf3
line source
1 #
2 # Symbol Table
3 #
5 import re
6 from Cython import Utils
7 from Errors import warning, error, InternalError
8 from StringEncoding import EncodedString
9 import Options, Naming
10 import PyrexTypes
11 from PyrexTypes import py_object_type
12 import TypeSlots
13 from TypeSlots import \
14 pyfunction_signature, pymethod_signature, \
15 get_special_method_signature, get_property_accessor_signature
16 import ControlFlow
17 import __builtin__
18 try:
19 set
20 except NameError:
21 from sets import Set as set
23 possible_identifier = re.compile(ur"(?![0-9])\w+$", re.U).match
24 nice_identifier = re.compile('^[a-zA-Z0-0_]+$').match
26 class BufferAux:
27 writable_needed = False
29 def __init__(self, buffer_info_var, stridevars, shapevars,
30 suboffsetvars):
31 self.buffer_info_var = buffer_info_var
32 self.stridevars = stridevars
33 self.shapevars = shapevars
34 self.suboffsetvars = suboffsetvars
36 def __repr__(self):
37 return "<BufferAux %r>" % self.__dict__
39 class Entry:
40 # A symbol table entry in a Scope or ModuleNamespace.
41 #
42 # name string Python name of entity
43 # cname string C name of entity
44 # type PyrexType Type of entity
45 # doc string Doc string
46 # init string Initial value
47 # visibility 'private' or 'public' or 'extern'
48 # is_builtin boolean Is an entry in the Python builtins dict
49 # is_cglobal boolean Is a C global variable
50 # is_pyglobal boolean Is a Python module-level variable
51 # or class attribute during
52 # class construction
53 # is_member boolean Is an assigned class member
54 # is_variable boolean Is a variable
55 # is_cfunction boolean Is a C function
56 # is_cmethod boolean Is a C method of an extension type
57 # is_unbound_cmethod boolean Is an unbound C method of an extension type
58 # is_type boolean Is a type definition
59 # is_const boolean Is a constant
60 # is_property boolean Is a property of an extension type:
61 # doc_cname string or None C const holding the docstring
62 # getter_cname string C func for getting property
63 # setter_cname string C func for setting or deleting property
64 # is_self_arg boolean Is the "self" arg of an exttype method
65 # is_arg boolean Is the arg of a method
66 # is_local boolean Is a local variable
67 # in_closure boolean Is referenced in an inner scope
68 # is_readonly boolean Can't be assigned to
69 # func_cname string C func implementing Python func
70 # pos position Source position where declared
71 # namespace_cname string If is_pyglobal, the C variable
72 # holding its home namespace
73 # pymethdef_cname string PyMethodDef structure
74 # signature Signature Arg & return types for Python func
75 # init_to_none boolean True if initial value should be None
76 # as_variable Entry Alternative interpretation of extension
77 # type name or builtin C function as a variable
78 # xdecref_cleanup boolean Use Py_XDECREF for error cleanup
79 # in_cinclude boolean Suppress C declaration code
80 # enum_values [Entry] For enum types, list of values
81 # qualified_name string "modname.funcname" or "modname.classname"
82 # or "modname.classname.funcname"
83 # is_declared_generic boolean Is declared as PyObject * even though its
84 # type is an extension type
85 # as_module None Module scope, if a cimported module
86 # is_inherited boolean Is an inherited attribute of an extension type
87 # pystring_cname string C name of Python version of string literal
88 # is_interned boolean For string const entries, value is interned
89 # is_identifier boolean For string const entries, value is an identifier
90 # used boolean
91 # is_special boolean Is a special method or property accessor
92 # of an extension type
93 # defined_in_pxd boolean Is defined in a .pxd file (not just declared)
94 # api boolean Generate C API for C class or function
95 # utility_code string Utility code needed when this entry is used
96 #
97 # buffer_aux BufferAux or None Extra information needed for buffer variables
99 borrowed = 0
100 init = ""
101 visibility = 'private'
102 is_builtin = 0
103 is_cglobal = 0
104 is_pyglobal = 0
105 is_member = 0
106 is_variable = 0
107 is_cfunction = 0
108 is_cmethod = 0
109 is_unbound_cmethod = 0
110 is_type = 0
111 is_const = 0
112 is_property = 0
113 doc_cname = None
114 getter_cname = None
115 setter_cname = None
116 is_self_arg = 0
117 is_arg = 0
118 is_local = 0
119 in_closure = 0
120 is_declared_generic = 0
121 is_readonly = 0
122 func_cname = None
123 doc = None
124 init_to_none = 0
125 as_variable = None
126 xdecref_cleanup = 0
127 in_cinclude = 0
128 as_module = None
129 is_inherited = 0
130 pystring_cname = None
131 is_identifier = 0
132 is_interned = 0
133 used = 0
134 is_special = 0
135 defined_in_pxd = 0
136 api = 0
137 utility_code = None
138 is_overridable = 0
139 buffer_aux = None
140 prev_entry = None
142 def __init__(self, name, cname, type, pos = None, init = None):
143 self.name = name
144 self.cname = cname
145 self.type = type
146 self.pos = pos
147 self.init = init
149 def redeclared(self, pos):
150 error(pos, "'%s' does not match previous declaration" % self.name)
151 error(self.pos, "Previous declaration is here")
153 class Scope:
154 # name string Unqualified name
155 # outer_scope Scope or None Enclosing scope
156 # entries {string : Entry} Python name to entry, non-types
157 # const_entries [Entry] Constant entries
158 # type_entries [Entry] Struct/union/enum/typedef/exttype entries
159 # sue_entries [Entry] Struct/union/enum entries
160 # arg_entries [Entry] Function argument entries
161 # var_entries [Entry] User-defined variable entries
162 # pyfunc_entries [Entry] Python function entries
163 # cfunc_entries [Entry] C function entries
164 # c_class_entries [Entry] All extension type entries
165 # temp_entries [Entry] Temporary variable entries
166 # free_temp_entries [Entry] Temp variables currently unused
167 # temp_counter integer Counter for naming temp vars
168 # cname_to_entry {string : Entry} Temp cname to entry mapping
169 # int_to_entry {int : Entry} Temp cname to entry mapping
170 # return_type PyrexType or None Return type of function owning scope
171 # is_py_class_scope boolean Is a Python class scope
172 # is_c_class_scope boolean Is an extension type scope
173 # scope_prefix string Disambiguator for C names
174 # in_cinclude boolean Suppress C declaration code
175 # qualified_name string "modname" or "modname.classname"
176 # pystring_entries [Entry] String const entries newly used as
177 # Python strings in this scope
178 # control_flow ControlFlow Used for keeping track of environment state
179 # nogil boolean In a nogil section
180 # directives dict Helper variable for the recursive
181 # analysis, contains directive values.
183 is_py_class_scope = 0
184 is_c_class_scope = 0
185 is_module_scope = 0
186 scope_prefix = ""
187 in_cinclude = 0
188 nogil = 0
189 directives = {}
191 temp_prefix = Naming.pyrex_prefix
193 def __init__(self, name, outer_scope, parent_scope):
194 # The outer_scope is the next scope in the lookup chain.
195 # The parent_scope is used to derive the qualified name of this scope.
196 self.name = name
197 self.outer_scope = outer_scope
198 self.parent_scope = parent_scope
199 mangled_name = "%d%s_" % (len(name), name)
200 qual_scope = self.qualifying_scope()
201 if qual_scope:
202 self.qualified_name = qual_scope.qualify_name(name)
203 self.scope_prefix = qual_scope.scope_prefix + mangled_name
204 else:
205 self.qualified_name = name
206 self.scope_prefix = mangled_name
207 self.entries = {}
208 self.const_entries = []
209 self.type_entries = []
210 self.sue_entries = []
211 self.arg_entries = []
212 self.var_entries = []
213 self.pyfunc_entries = []
214 self.cfunc_entries = []
215 self.c_class_entries = []
216 self.defined_c_classes = []
217 self.imported_c_classes = {}
218 self.temp_entries = []
219 self.free_temp_entries = []
220 #self.pending_temp_entries = [] # TEMPORARY
221 self.temp_counter = 1
222 self.cname_to_entry = {}
223 self.string_to_entry = {}
224 self.identifier_to_entry = {}
225 self.num_to_entry = {}
226 self.obj_to_entry = {}
227 self.pystring_entries = []
228 self.buffer_entries = []
229 self.control_flow = ControlFlow.LinearControlFlow()
231 def start_branching(self, pos):
232 self.control_flow = self.control_flow.start_branch(pos)
234 def next_branch(self, pos):
235 self.control_flow = self.control_flow.next_branch(pos)
237 def finish_branching(self, pos):
238 self.control_flow = self.control_flow.finish_branch(pos)
240 def __str__(self):
241 return "<%s %s>" % (self.__class__.__name__, self.qualified_name)
243 def intern_identifier(self, name):
244 return self.global_scope().intern_identifier(name)
246 def qualifying_scope(self):
247 return self.parent_scope
249 def mangle(self, prefix, name = None):
250 if name:
251 return "%s%s%s" % (prefix, self.scope_prefix, name)
252 else:
253 return self.parent_scope.mangle(prefix, self.name)
255 def mangle_internal(self, name):
256 # Mangle an internal name so as not to clash with any
257 # user-defined name in this scope.
258 prefix = "%s%s_" % (Naming.pyrex_prefix, name)
259 return self.mangle(prefix)
260 #return self.parent_scope.mangle(prefix, self.name)
262 def global_scope(self):
263 # Return the module-level scope containing this scope.
264 return self.outer_scope.global_scope()
266 def builtin_scope(self):
267 # Return the module-level scope containing this scope.
268 return self.outer_scope.builtin_scope()
270 def declare(self, name, cname, type, pos, visibility):
271 # Create new entry, and add to dictionary if
272 # name is not None. Reports a warning if already
273 # declared.
274 if not self.in_cinclude and cname and re.match("^_[_A-Z]+$", cname):
275 # See http://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html#Reserved-Names
276 warning(pos, "'%s' is a reserved name in C." % cname, -1)
277 dict = self.entries
278 if name and dict.has_key(name):
279 if visibility == 'extern':
280 warning(pos, "'%s' redeclared " % name, 0)
281 elif visibility != 'ignore':
282 error(pos, "'%s' redeclared " % name)
283 entry = Entry(name, cname, type, pos = pos)
284 entry.in_cinclude = self.in_cinclude
285 if name:
286 entry.qualified_name = self.qualify_name(name)
287 dict[name] = entry
288 entry.scope = self
289 entry.visibility = visibility
290 return entry
292 def qualify_name(self, name):
293 return "%s.%s" % (self.qualified_name, name)
295 def declare_const(self, name, type, value, pos, cname = None, visibility = 'private'):
296 # Add an entry for a named constant.
297 if not cname:
298 if self.in_cinclude:
299 cname = name
300 else:
301 cname = self.mangle(Naming.enum_prefix, name)
302 entry = self.declare(name, cname, type, pos, visibility)
303 entry.is_const = 1
304 entry.value = value
305 return entry
307 def declare_type(self, name, type, pos,
308 cname = None, visibility = 'private', defining = 1):
309 # Add an entry for a type definition.
310 if not cname:
311 cname = name
312 entry = self.declare(name, cname, type, pos, visibility)
313 entry.is_type = 1
314 if defining:
315 self.type_entries.append(entry)
316 # here we would set as_variable to an object representing this type
317 return entry
319 def declare_typedef(self, name, base_type, pos, cname = None,
320 visibility = 'private'):
321 if not cname:
322 if self.in_cinclude or visibility == 'public':
323 cname = name
324 else:
325 cname = self.mangle(Naming.type_prefix, name)
326 type = PyrexTypes.CTypedefType(cname, base_type)
327 entry = self.declare_type(name, type, pos, cname, visibility)
328 type.qualified_name = entry.qualified_name
329 return entry
331 def declare_struct_or_union(self, name, kind, scope,
332 typedef_flag, pos, cname = None, visibility = 'private'):
333 # Add an entry for a struct or union definition.
334 if not cname:
335 if self.in_cinclude or visibility == 'public':
336 cname = name
337 else:
338 cname = self.mangle(Naming.type_prefix, name)
339 entry = self.lookup_here(name)
340 if not entry:
341 type = PyrexTypes.CStructOrUnionType(
342 name, kind, scope, typedef_flag, cname)
343 entry = self.declare_type(name, type, pos, cname,
344 visibility = visibility, defining = scope is not None)
345 self.sue_entries.append(entry)
346 else:
347 if not (entry.is_type and entry.type.is_struct_or_union
348 and entry.type.kind == kind):
349 warning(pos, "'%s' redeclared " % name, 0)
350 elif scope and entry.type.scope:
351 warning(pos, "'%s' already defined (ignoring second definition)" % name, 0)
352 else:
353 self.check_previous_typedef_flag(entry, typedef_flag, pos)
354 self.check_previous_visibility(entry, visibility, pos)
355 if scope:
356 entry.type.scope = scope
357 self.type_entries.append(entry)
358 if not scope and not entry.type.scope:
359 self.check_for_illegal_incomplete_ctypedef(typedef_flag, pos)
360 return entry
362 def check_previous_typedef_flag(self, entry, typedef_flag, pos):
363 if typedef_flag != entry.type.typedef_flag:
364 error(pos, "'%s' previously declared using '%s'" % (
365 entry.name, ("cdef", "ctypedef")[entry.type.typedef_flag]))
367 def check_previous_visibility(self, entry, visibility, pos):
368 if entry.visibility != visibility:
369 error(pos, "'%s' previously declared as '%s'" % (
370 entry.name, entry.visibility))
372 def declare_enum(self, name, pos, cname, typedef_flag,
373 visibility = 'private'):
374 if name:
375 if not cname:
376 if self.in_cinclude or visibility == 'public':
377 cname = name
378 else:
379 cname = self.mangle(Naming.type_prefix, name)
380 type = PyrexTypes.CEnumType(name, cname, typedef_flag)
381 else:
382 type = PyrexTypes.c_anon_enum_type
383 entry = self.declare_type(name, type, pos, cname = cname,
384 visibility = visibility)
385 entry.enum_values = []
386 self.sue_entries.append(entry)
387 return entry
389 def declare_var(self, name, type, pos,
390 cname = None, visibility = 'private', is_cdef = 0):
391 # Add an entry for a variable.
392 if not cname:
393 if visibility != 'private':
394 cname = name
395 else:
396 cname = self.mangle(Naming.var_prefix, name)
397 entry = self.declare(name, cname, type, pos, visibility)
398 entry.is_variable = 1
399 self.control_flow.set_state((), (name, 'initalized'), False)
400 return entry
402 def declare_builtin(self, name, pos):
403 return self.outer_scope.declare_builtin(name, pos)
405 def declare_pyfunction(self, name, pos):
406 # Add an entry for a Python function.
407 entry = self.lookup_here(name)
408 if entry and not entry.type.is_cfunction:
409 # This is legal Python, but for now will produce invalid C.
410 error(pos, "'%s' already declared" % name)
411 entry = self.declare_var(name, py_object_type, pos, visibility='extern')
412 entry.signature = pyfunction_signature
413 self.pyfunc_entries.append(entry)
414 return entry
416 def register_pyfunction(self, entry):
417 self.pyfunc_entries.append(entry)
419 def declare_cfunction(self, name, type, pos,
420 cname = None, visibility = 'private', defining = 0, api = 0, in_pxd = 0):
421 # Add an entry for a C function.
422 entry = self.lookup_here(name)
423 if entry:
424 if visibility != 'private' and visibility != entry.visibility:
425 warning(pos, "Function '%s' previously declared as '%s'" % (name, entry.visibility), 1)
426 if not entry.type.same_as(type):
427 if visibility == 'extern' and entry.visibility == 'extern':
428 warning(pos, "Function signature does not match previous declaration", 1)
429 entry.type = type
430 else:
431 error(pos, "Function signature does not match previous declaration")
432 else:
433 if not cname:
434 if api or visibility != 'private':
435 cname = name
436 else:
437 cname = self.mangle(Naming.func_prefix, name)
438 entry = self.add_cfunction(name, type, pos, cname, visibility)
439 entry.func_cname = cname
440 if in_pxd and visibility != 'extern':
441 entry.defined_in_pxd = 1
442 if api:
443 entry.api = 1
444 if not defining and not in_pxd and visibility != 'extern':
445 error(pos, "Non-extern C function '%s' declared but not defined" % name)
446 return entry
448 def add_cfunction(self, name, type, pos, cname, visibility):
449 # Add a C function entry without giving it a func_cname.
450 entry = self.declare(name, cname, type, pos, visibility)
451 entry.is_cfunction = 1
452 self.cfunc_entries.append(entry)
453 return entry
455 def find(self, name, pos):
456 # Look up name, report error if not found.
457 entry = self.lookup(name)
458 if entry:
459 return entry
460 else:
461 error(pos, "'%s' is not declared" % name)
463 def find_imported_module(self, path, pos):
464 # Look up qualified name, must be a module, report error if not found.
465 # Path is a list of names.
466 scope = self
467 for name in path:
468 entry = scope.find(name, pos)
469 if not entry:
470 return None
471 if entry.as_module:
472 scope = entry.as_module
473 else:
474 error(pos, "'%s' is not a cimported module" % scope.qualified_name)
475 return None
476 return scope
478 def lookup(self, name):
479 # Look up name in this scope or an enclosing one.
480 # Return None if not found.
481 return (self.lookup_here(name)
482 or (self.outer_scope and self.outer_scope.lookup_from_inner(name))
483 or None)
485 def lookup_from_inner(self, name):
486 # Look up name in this scope or an enclosing one.
487 # This is only called from enclosing scopes.
488 return (self.lookup_here(name)
489 or (self.outer_scope and self.outer_scope.lookup_from_inner(name))
490 or None)
492 def lookup_here(self, name):
493 # Look up in this scope only, return None if not found.
494 return self.entries.get(name, None)
496 def lookup_target(self, name):
497 # Look up name in this scope only. Declare as Python
498 # variable if not found.
499 entry = self.lookup_here(name)
500 if not entry:
501 entry = self.declare_var(name, py_object_type, None)
502 return entry
504 def add_string_const(self, value, identifier = False):
505 # Add an entry for a string constant.
506 if identifier:
507 cname = self.new_string_const_cname(value)
508 else:
509 cname = self.new_const_cname()
510 if value.is_unicode:
511 c_type = PyrexTypes.c_utf8_char_array_type
512 value = value.utf8encode()
513 else:
514 c_type = PyrexTypes.c_char_array_type
515 value = value.byteencode()
516 entry = Entry("", cname, c_type, init = value)
517 entry.used = 1
518 self.const_entries.append(entry)
519 return entry
521 def get_string_const(self, value, identifier = False):
522 # Get entry for string constant. Returns an existing
523 # one if possible, otherwise creates a new one.
524 genv = self.global_scope()
525 if identifier:
526 string_map = genv.identifier_to_entry
527 else:
528 string_map = genv.string_to_entry
529 entry = string_map.get(value)
530 if not entry:
531 entry = self.add_string_const(value, identifier)
532 entry.is_identifier = identifier
533 string_map[value] = entry
534 return entry
536 def add_py_string(self, entry, identifier = None):
537 # If not already done, allocate a C name for a Python version of
538 # a string literal, and add it to the list of Python strings to
539 # be created at module init time. If the string resembles a
540 # Python identifier, it will be interned.
541 if entry.pystring_cname:
542 return
543 value = entry.init
544 entry.pystring_cname = Naming.py_const_prefix + entry.cname[len(Naming.const_prefix):]
545 self.pystring_entries.append(entry)
546 self.global_scope().all_pystring_entries.append(entry)
547 if identifier or (identifier is None and possible_identifier(value)):
548 entry.is_interned = 1
549 self.global_scope().new_interned_string_entries.append(entry)
551 def add_py_num(self, value):
552 # Add an entry for an int constant.
553 cname = "%s%s" % (Naming.interned_num_prefix, value)
554 cname = cname.replace('-', 'neg_').replace('.','_')
555 entry = Entry("", cname, py_object_type, init = value)
556 entry.used = 1
557 entry.is_interned = 1
558 self.const_entries.append(entry)
559 self.interned_nums.append(entry)
560 return entry
562 def get_py_num(self, value, longness):
563 # Get entry for int constant. Returns an existing
564 # one if possible, otherwise creates a new one.
565 if longness or Utils.long_literal(value):
566 value += "L"
567 genv = self.global_scope()
568 entry = genv.num_to_entry.get(value)
569 if not entry:
570 entry = genv.add_py_num(value)
571 genv.num_to_entry[value] = entry
572 genv.pynum_entries.append(entry)
573 return entry
575 def get_py_obj(self, obj, c_prefix=''):
576 # Get entry for a generic constant. Returns an existing
577 # one if possible, otherwise creates a new one.
578 genv = self.global_scope()
579 entry = genv.obj_to_entry.get(obj)
580 if not entry:
581 entry = genv.add_py_num(obj, c_prefix)
582 genv.obj_to_entry[obj] = entry
583 return entry
585 def new_string_const_cname(self, value):
586 # Create a new globally-unique nice name for a string constant.
587 if len(value) < 20 and nice_identifier(value):
588 return "%s%s" % (Naming.const_prefix, value)
589 else:
590 return self.global_scope().new_const_cname()
592 def new_const_cname(self):
593 # Create a new globally-unique name for a constant.
594 return self.global_scope().new_const_cname()
596 def allocate_temp(self, type):
597 # Allocate a temporary variable of the given type from the
598 # free list if available, otherwise create a new one.
599 # Returns the cname of the variable.
600 for entry in self.free_temp_entries:
601 if entry.type == type:
602 self.free_temp_entries.remove(entry)
603 return entry.cname
604 n = self.temp_counter
605 self.temp_counter = n + 1
606 cname = "%s%d" % (self.temp_prefix, n)
607 entry = Entry("", cname, type)
608 entry.used = 1
609 if type.is_pyobject or type == PyrexTypes.c_py_ssize_t_type:
610 entry.init = "0"
611 self.cname_to_entry[entry.cname] = entry
612 self.temp_entries.append(entry)
613 return entry.cname
615 def allocate_temp_pyobject(self):
616 # Allocate a temporary PyObject variable.
617 return self.allocate_temp(py_object_type)
619 def release_temp(self, cname):
620 # Release a temporary variable for re-use.
621 if not cname: # can happen when type of an expr is void
622 return
623 entry = self.cname_to_entry[cname]
624 if entry in self.free_temp_entries:
625 raise InternalError("Temporary variable %s released more than once"
626 % cname)
627 self.free_temp_entries.append(entry)
629 def temps_in_use(self):
630 # Return a new list of temp entries currently in use.
631 return [entry for entry in self.temp_entries
632 if entry not in self.free_temp_entries]
634 def use_utility_code(self, new_code, name=None):
635 self.global_scope().use_utility_code(new_code, name)
637 def generate_library_function_declarations(self, code):
638 # Generate extern decls for C library funcs used.
639 pass
641 def defines_any(self, names):
642 # Test whether any of the given names are
643 # defined in this scope.
644 for name in names:
645 if name in self.entries:
646 return 1
647 return 0
649 class PreImportScope(Scope):
651 namespace_cname = Naming.preimport_cname
653 def __init__(self):
654 Scope.__init__(self, Options.pre_import, None, None)
656 def declare_builtin(self, name, pos):
657 entry = self.declare(name, name, py_object_type, pos, 'private')
658 entry.is_variable = True
659 entry.is_pyglobal = True
660 return entry
663 class BuiltinScope(Scope):
664 # The builtin namespace.
666 def __init__(self):
667 if Options.pre_import is None:
668 Scope.__init__(self, "__builtin__", None, None)
669 else:
670 Scope.__init__(self, "__builtin__", PreImportScope(), None)
671 self.type_names = {}
673 for name, definition in self.builtin_entries.iteritems():
674 cname, type = definition
675 self.declare_var(name, type, None, cname)
677 def declare_builtin(self, name, pos):
678 if not hasattr(__builtin__, name):
679 if self.outer_scope is not None:
680 return self.outer_scope.declare_builtin(name, pos)
681 else:
682 error(pos, "undeclared name not builtin: %s"%name)
684 def declare_builtin_cfunction(self, name, type, cname, python_equiv = None,
685 utility_code = None):
686 # If python_equiv == "*", the Python equivalent has the same name
687 # 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, visibility='extern')
690 entry.utility_code = utility_code
691 if python_equiv:
692 if python_equiv == "*":
693 python_equiv = name
694 else:
695 python_equiv = EncodedString(python_equiv)
696 var_entry = Entry(python_equiv, python_equiv, py_object_type)
697 var_entry.is_variable = 1
698 var_entry.is_builtin = 1
699 entry.as_variable = var_entry
700 return entry
702 def declare_builtin_type(self, name, cname):
703 name = EncodedString(name)
704 type = PyrexTypes.BuiltinObjectType(name, cname)
705 type.set_scope(CClassScope(name, outer_scope=None, visibility='extern'))
706 self.type_names[name] = 1
707 entry = self.declare_type(name, type, None, visibility='extern')
709 var_entry = Entry(name = entry.name,
710 type = self.lookup('type').type, # make sure "type" is the first type declared...
711 pos = entry.pos,
712 cname = "((PyObject*)%s)" % entry.type.typeptr_cname)
713 var_entry.is_variable = 1
714 var_entry.is_cglobal = 1
715 var_entry.is_readonly = 1
716 entry.as_variable = var_entry
718 return type
720 def builtin_scope(self):
721 return self
723 builtin_entries = {
725 "type": ["((PyObject*)&PyType_Type)", py_object_type],
727 "bool": ["((PyObject*)&PyBool_Type)", py_object_type],
728 "int": ["((PyObject*)&PyInt_Type)", py_object_type],
729 "long": ["((PyObject*)&PyLong_Type)", py_object_type],
730 "float": ["((PyObject*)&PyFloat_Type)", py_object_type],
731 "complex":["((PyObject*)&PyComplex_Type)", py_object_type],
733 "bytes": ["((PyObject*)&PyBytes_Type)", py_object_type],
734 "str": ["((PyObject*)&PyString_Type)", py_object_type],
735 "unicode":["((PyObject*)&PyUnicode_Type)", py_object_type],
737 "tuple": ["((PyObject*)&PyTuple_Type)", py_object_type],
738 "list": ["((PyObject*)&PyList_Type)", py_object_type],
739 "dict": ["((PyObject*)&PyDict_Type)", py_object_type],
740 "set": ["((PyObject*)&PySet_Type)", py_object_type],
741 "frozenset": ["((PyObject*)&PyFrozenSet_Type)", py_object_type],
743 "slice": ["((PyObject*)&PySlice_Type)", py_object_type],
744 "file": ["((PyObject*)&PyFile_Type)", py_object_type],
746 "None": ["Py_None", py_object_type],
747 "False": ["Py_False", py_object_type],
748 "True": ["Py_True", py_object_type],
749 }
751 const_counter = 1 # As a temporary solution for compiling code in pxds
753 class ModuleScope(Scope):
754 # module_name string Python name of the module
755 # module_cname string C name of Python module object
756 # #module_dict_cname string C name of module dict object
757 # method_table_cname string C name of method table
758 # doc string Module doc string
759 # doc_cname string C name of module doc string
760 # const_counter integer Counter for naming constants (PS: MOVED TO GLOBAL)
761 # utility_code_list [((string, string), string)] Queuing utility codes for forwarding to Code.py
762 # default_entries [Entry] Function argument default entries
763 # python_include_files [string] Standard Python headers to be included
764 # include_files [string] Other C headers to be included
765 # string_to_entry {string : Entry} Map string const to entry
766 # identifier_to_entry {string : Entry} Map identifier string const to entry
767 # context Context
768 # parent_module Scope Parent in the import namespace
769 # module_entries {string : Entry} For cimport statements
770 # type_names {string : 1} Set of type names (used during parsing)
771 # included_files [string] Cython sources included with 'include'
772 # pxd_file_loaded boolean Corresponding .pxd file has been processed
773 # cimported_modules [ModuleScope] Modules imported with cimport
774 # new_interned_string_entries [Entry] New interned strings waiting to be declared
775 # interned_nums [int/long] Interned numeric constants
776 # all_pystring_entries [Entry] Python string consts from all scopes
777 # types_imported {PyrexType : 1} Set of types for which import code generated
778 # has_import_star boolean Module contains import *
780 is_module_scope = 1
781 has_import_star = 0
783 def __init__(self, name, parent_module, context):
784 self.parent_module = parent_module
785 outer_scope = context.find_submodule("__builtin__")
786 Scope.__init__(self, name, outer_scope, parent_module)
787 self.module_name = name
788 self.context = context
789 self.module_cname = Naming.module_cname
790 self.module_dict_cname = Naming.moddict_cname
791 self.method_table_cname = Naming.methtable_cname
792 self.doc = ""
793 self.doc_cname = Naming.moddoc_cname
794 self.utility_code_list = []
795 self.default_entries = []
796 self.module_entries = {}
797 self.python_include_files = ["Python.h", "structmember.h"]
798 self.include_files = []
799 self.type_names = dict(outer_scope.type_names)
800 self.pxd_file_loaded = 0
801 self.cimported_modules = []
802 self.new_interned_string_entries = []
803 self.interned_nums = []
804 self.interned_objs = []
805 self.all_pystring_entries = []
806 self.types_imported = {}
807 self.included_files = []
808 self.pynum_entries = []
809 self.has_extern_class = 0
810 self.cached_builtins = []
811 self.undeclared_cached_builtins = []
812 self.namespace_cname = self.module_cname
814 def qualifying_scope(self):
815 return self.parent_module
817 def global_scope(self):
818 return self
820 def declare_builtin(self, name, pos):
821 if not hasattr(__builtin__, name):
822 if self.has_import_star:
823 entry = self.declare_var(name, py_object_type, pos)
824 return entry
825 elif self.outer_scope is not None:
826 return self.outer_scope.declare_builtin(name, pos)
827 else:
828 error(pos, "undeclared name not builtin: %s"%name)
829 if Options.cache_builtins:
830 for entry in self.cached_builtins:
831 if entry.name == name:
832 return entry
833 entry = self.declare(None, None, py_object_type, pos, 'private')
834 if Options.cache_builtins:
835 entry.is_builtin = 1
836 entry.is_const = 1
837 entry.name = name
838 entry.cname = Naming.builtin_prefix + name
839 self.cached_builtins.append(entry)
840 self.undeclared_cached_builtins.append(entry)
841 else:
842 entry.is_builtin = 1
843 return entry
845 def intern_identifier(self, name):
846 string_entry = self.get_string_const(name, identifier = True)
847 self.add_py_string(string_entry, identifier = 1)
848 return string_entry.pystring_cname
850 def find_module(self, module_name, pos):
851 # Find a module in the import namespace, interpreting
852 # relative imports relative to this module's parent.
853 # Finds and parses the module's .pxd file if the module
854 # has not been referenced before.
855 return self.global_scope().context.find_module(
856 module_name, relative_to = self.parent_module, pos = pos)
858 def find_submodule(self, name):
859 # Find and return scope for a submodule of this module,
860 # creating a new empty one if necessary. Doesn't parse .pxd.
861 scope = self.lookup_submodule(name)
862 if not scope:
863 scope = ModuleScope(name,
864 parent_module = self, context = self.context)
865 self.module_entries[name] = scope
866 return scope
868 def lookup_submodule(self, name):
869 # Return scope for submodule of this module, or None.
870 return self.module_entries.get(name, None)
872 def add_include_file(self, filename):
873 if filename not in self.python_include_files \
874 and filename not in self.include_files:
875 self.include_files.append(filename)
877 def add_imported_module(self, scope):
878 if scope not in self.cimported_modules:
879 self.cimported_modules.append(scope)
881 def add_imported_entry(self, name, entry, pos):
882 if entry not in self.entries:
883 self.entries[name] = entry
884 else:
885 warning(pos, "'%s' redeclared " % name, 0)
887 def declare_module(self, name, scope, pos):
888 # Declare a cimported module. This is represented as a
889 # Python module-level variable entry with a module
890 # scope attached to it. Reports an error and returns
891 # None if previously declared as something else.
892 entry = self.lookup_here(name)
893 if entry:
894 if entry.is_pyglobal and entry.as_module is scope:
895 return entry # Already declared as the same module
896 if not (entry.is_pyglobal and not entry.as_module):
897 # SAGE -- I put this here so Pyrex
898 # cimport's work across directories.
899 # Currently it tries to multiply define
900 # every module appearing in an import list.
901 # It shouldn't be an error for a module
902 # name to appear again, and indeed the generated
903 # code compiles fine.
904 return entry
905 warning(pos, "'%s' redeclared " % name, 0)
906 return None
907 else:
908 entry = self.declare_var(name, py_object_type, pos)
909 entry.as_module = scope
910 self.cimported_modules.append(scope)
911 return entry
913 def declare_var(self, name, type, pos,
914 cname = None, visibility = 'private', is_cdef = 0):
915 # Add an entry for a global variable. If it is a Python
916 # object type, and not declared with cdef, it will live
917 # in the module dictionary, otherwise it will be a C
918 # global variable.
919 entry = Scope.declare_var(self, name, type, pos,
920 cname, visibility, is_cdef)
921 if not visibility in ('private', 'public', 'extern'):
922 error(pos, "Module-level variable cannot be declared %s" % visibility)
923 if not is_cdef:
924 if not (type.is_pyobject and not type.is_extension_type):
925 raise InternalError(
926 "Non-cdef global variable is not a generic Python object")
927 entry.is_pyglobal = 1
928 else:
929 entry.is_cglobal = 1
930 self.var_entries.append(entry)
931 return entry
933 def declare_global(self, name, pos):
934 entry = self.lookup_here(name)
935 if not entry:
936 self.declare_var(name, py_object_type, pos)
938 def add_default_value(self, type):
939 # Add an entry for holding a function argument
940 # default value.
941 cname = self.new_const_cname()
942 entry = Entry("", cname, type)
943 self.default_entries.append(entry)
944 return entry
946 def new_const_cname(self):
947 global const_counter
948 # Create a new globally-unique name for a constant.
949 prefix=''
950 n = const_counter
951 const_counter = n + 1
952 return "%s%s%d" % (Naming.const_prefix, prefix, n)
954 def use_utility_code(self, new_code, name=None):
955 self.utility_code_list.append((new_code, name))
957 def declare_c_class(self, name, pos, defining = 0, implementing = 0,
958 module_name = None, base_type = None, objstruct_cname = None,
959 typeobj_cname = None, visibility = 'private', typedef_flag = 0, api = 0,
960 buffer_defaults = None):
961 #
962 # Look for previous declaration as a type
963 #
964 entry = self.lookup_here(name)
965 if entry:
966 type = entry.type
967 if not (entry.is_type and type.is_extension_type):
968 entry = None # Will cause redeclaration and produce an error
969 else:
970 scope = type.scope
971 if typedef_flag and (not scope or scope.defined):
972 self.check_previous_typedef_flag(entry, typedef_flag, pos)
973 if (scope and scope.defined) or (base_type and type.base_type):
974 if base_type and base_type is not type.base_type:
975 error(pos, "Base type does not match previous declaration")
976 if base_type and not type.base_type:
977 type.base_type = base_type
978 #
979 # Make a new entry if needed
980 #
981 if not entry:
982 type = PyrexTypes.PyExtensionType(name, typedef_flag, base_type)
983 type.pos = pos
984 type.buffer_defaults = buffer_defaults
985 if visibility == 'extern':
986 type.module_name = module_name
987 else:
988 type.module_name = self.qualified_name
989 type.typeptr_cname = self.mangle(Naming.typeptr_prefix, name)
990 entry = self.declare_type(name, type, pos, visibility = visibility,
991 defining = 0)
992 if objstruct_cname:
993 type.objstruct_cname = objstruct_cname
994 elif not entry.in_cinclude:
995 type.objstruct_cname = self.mangle(Naming.objstruct_prefix, name)
996 else:
997 error(entry.pos,
998 "Object name required for 'public' or 'extern' C class")
999 self.attach_var_entry_to_c_class(entry)
1000 self.c_class_entries.append(entry)
1002 # Check for re-definition and create scope if needed
1004 if not type.scope:
1005 if defining or implementing:
1006 scope = CClassScope(name = name, outer_scope = self,
1007 visibility = visibility)
1008 if base_type:
1009 scope.declare_inherited_c_attributes(base_type.scope)
1010 type.set_scope(scope)
1011 self.type_entries.append(entry)
1012 else:
1013 self.check_for_illegal_incomplete_ctypedef(typedef_flag, pos)
1014 else:
1015 if defining and type.scope.defined:
1016 error(pos, "C class '%s' already defined" % name)
1017 elif implementing and type.scope.implemented:
1018 error(pos, "C class '%s' already implemented" % name)
1020 # Fill in options, checking for compatibility with any previous declaration
1022 if defining:
1023 entry.defined_in_pxd = 1
1024 if implementing: # So that filenames in runtime exceptions refer to
1025 entry.pos = pos # the .pyx file and not the .pxd file
1026 if visibility != 'private' and entry.visibility != visibility:
1027 error(pos, "Class '%s' previously declared as '%s'"
1028 % (name, entry.visibility))
1029 if api:
1030 entry.api = 1
1031 if objstruct_cname:
1032 if type.objstruct_cname and type.objstruct_cname != objstruct_cname:
1033 error(pos, "Object struct name differs from previous declaration")
1034 type.objstruct_cname = objstruct_cname
1035 if typeobj_cname:
1036 if type.typeobj_cname and type.typeobj_cname != typeobj_cname:
1037 error(pos, "Type object name differs from previous declaration")
1038 type.typeobj_cname = typeobj_cname
1040 # Return new or existing entry
1042 return entry
1044 def check_for_illegal_incomplete_ctypedef(self, typedef_flag, pos):
1045 if typedef_flag and not self.in_cinclude:
1046 error(pos, "Forward-referenced type must use 'cdef', not 'ctypedef'")
1048 def allocate_vtable_names(self, entry):
1049 # If extension type has a vtable, allocate vtable struct and
1050 # slot names for it.
1051 type = entry.type
1052 if type.base_type and type.base_type.vtabslot_cname:
1053 #print "...allocating vtabslot_cname because base type has one" ###
1054 type.vtabslot_cname = "%s.%s" % (
1055 Naming.obj_base_cname, type.base_type.vtabslot_cname)
1056 elif type.scope and type.scope.cfunc_entries:
1057 #print "...allocating vtabslot_cname because there are C methods" ###
1058 type.vtabslot_cname = Naming.vtabslot_cname
1059 if type.vtabslot_cname:
1060 #print "...allocating other vtable related cnames" ###
1061 type.vtabstruct_cname = self.mangle(Naming.vtabstruct_prefix, entry.name)
1062 type.vtabptr_cname = self.mangle(Naming.vtabptr_prefix, entry.name)
1064 def check_c_classes(self):
1065 # Performs post-analysis checking and finishing up of extension types
1066 # being implemented in this module. This is called only for the main
1067 # .pyx file scope, not for cimported .pxd scopes.
1069 # Checks all extension types declared in this scope to
1070 # make sure that:
1072 # * The extension type is implemented
1073 # * All required object and type names have been specified or generated
1074 # * All non-inherited C methods are implemented
1076 # Also allocates a name for the vtable if needed.
1078 debug_check_c_classes = 0
1079 if debug_check_c_classes:
1080 print("Scope.check_c_classes: checking scope " + self.qualified_name)
1081 for entry in self.c_class_entries:
1082 if debug_check_c_classes:
1083 print("...entry %s %s" % (entry.name, entry))
1084 print("......type = " + entry.type)
1085 print("......visibility = " + entry.visibility)
1086 type = entry.type
1087 name = entry.name
1088 visibility = entry.visibility
1089 # Check defined
1090 if not type.scope:
1091 error(entry.pos, "C class '%s' is declared but not defined" % name)
1092 # Generate typeobj_cname
1093 if visibility != 'extern' and not type.typeobj_cname:
1094 type.typeobj_cname = self.mangle(Naming.typeobj_prefix, name)
1095 ## Generate typeptr_cname
1096 #type.typeptr_cname = self.mangle(Naming.typeptr_prefix, name)
1097 # Check C methods defined
1098 if type.scope:
1099 for method_entry in type.scope.cfunc_entries:
1100 if not method_entry.is_inherited and not method_entry.func_cname:
1101 error(method_entry.pos, "C method '%s' is declared but not defined" %
1102 method_entry.name)
1103 # Allocate vtable name if necessary
1104 if type.vtabslot_cname:
1105 #print "ModuleScope.check_c_classes: allocating vtable cname for", self ###
1106 type.vtable_cname = self.mangle(Naming.vtable_prefix, entry.name)
1108 def attach_var_entry_to_c_class(self, entry):
1109 # The name of an extension class has to serve as both a type
1110 # name and a variable name holding the type object. It is
1111 # represented in the symbol table by a type entry with a
1112 # variable entry attached to it. For the variable entry,
1113 # we use a read-only C global variable whose name is an
1114 # expression that refers to the type object.
1115 import Builtin
1116 var_entry = Entry(name = entry.name,
1117 type = Builtin.type_type,
1118 pos = entry.pos,
1119 cname = "((PyObject*)%s)" % entry.type.typeptr_cname)
1120 var_entry.is_variable = 1
1121 var_entry.is_cglobal = 1
1122 var_entry.is_readonly = 1
1123 entry.as_variable = var_entry
1125 class LocalScope(Scope):
1127 def __init__(self, name, outer_scope):
1128 Scope.__init__(self, name, outer_scope, outer_scope)
1130 def mangle(self, prefix, name):
1131 return prefix + name
1133 def declare_arg(self, name, type, pos):
1134 # Add an entry for an argument of a function.
1135 cname = self.mangle(Naming.var_prefix, name)
1136 entry = self.declare(name, cname, type, pos, 'private')
1137 entry.is_variable = 1
1138 if type.is_pyobject:
1139 entry.init = "0"
1140 entry.is_arg = 1
1141 #entry.borrowed = 1 # Not using borrowed arg refs for now
1142 self.arg_entries.append(entry)
1143 self.control_flow.set_state((), (name, 'source'), 'arg')
1144 return entry
1146 def declare_var(self, name, type, pos,
1147 cname = None, visibility = 'private', is_cdef = 0):
1148 # Add an entry for a local variable.
1149 if visibility in ('public', 'readonly'):
1150 error(pos, "Local variable cannot be declared %s" % visibility)
1151 entry = Scope.declare_var(self, name, type, pos,
1152 cname, visibility, is_cdef)
1153 if type.is_pyobject and not Options.init_local_none:
1154 entry.init = "0"
1155 entry.init_to_none = type.is_pyobject and Options.init_local_none
1156 entry.is_local = 1
1157 self.var_entries.append(entry)
1158 return entry
1160 def declare_global(self, name, pos):
1161 # Pull entry from global scope into local scope.
1162 if self.lookup_here(name):
1163 warning(pos, "'%s' redeclared ", 0)
1164 else:
1165 entry = self.global_scope().lookup_target(name)
1166 self.entries[name] = entry
1168 def lookup_from_inner(self, name):
1169 entry = self.lookup_here(name)
1170 if entry:
1171 entry.in_closure = 1
1172 return entry
1173 else:
1174 return (self.outer_scope and self.outer_scope.lookup_from_inner(name)) or None
1176 def mangle_closure_cnames(self, scope_var):
1177 for entry in self.entries.values():
1178 if entry.in_closure:
1179 if not hasattr(entry, 'orig_cname'):
1180 entry.orig_cname = entry.cname
1181 entry.cname = scope_var + "->" + entry.cname
1184 class GeneratorLocalScope(LocalScope):
1186 temp_prefix = Naming.cur_scope_cname + "->" + LocalScope.temp_prefix
1188 def mangle_closure_cnames(self, scope_var):
1189 for entry in self.entries.values() + self.temp_entries:
1190 entry.in_closure = 1
1191 LocalScope.mangle_closure_cnames(self, scope_var)
1193 # def mangle(self, prefix, name):
1194 # return "%s->%s" % (Naming.scope_obj_cname, name)
1196 class StructOrUnionScope(Scope):
1197 # Namespace of a C struct or union.
1199 def __init__(self, name="?"):
1200 Scope.__init__(self, name, None, None)
1202 def declare_var(self, name, type, pos,
1203 cname = None, visibility = 'private', is_cdef = 0, allow_pyobject = 0):
1204 # Add an entry for an attribute.
1205 if not cname:
1206 cname = name
1207 if type.is_cfunction:
1208 type = PyrexTypes.CPtrType(type)
1209 entry = self.declare(name, cname, type, pos, visibility)
1210 entry.is_variable = 1
1211 self.var_entries.append(entry)
1212 if type.is_pyobject and not allow_pyobject:
1213 error(pos,
1214 "C struct/union member cannot be a Python object")
1215 if visibility != 'private':
1216 error(pos,
1217 "C struct/union member cannot be declared %s" % visibility)
1218 return entry
1220 def declare_cfunction(self, name, type, pos,
1221 cname = None, visibility = 'private', defining = 0, api = 0, in_pxd = 0):
1222 self.declare_var(name, type, pos, cname, visibility)
1224 class ClassScope(Scope):
1225 # Abstract base class for namespace of
1226 # Python class or extension type.
1228 # class_name string Pyrex name of the class
1229 # scope_prefix string Additional prefix for names
1230 # declared in the class
1231 # doc string or None Doc string
1233 def __init__(self, name, outer_scope):
1234 Scope.__init__(self, name, outer_scope, outer_scope)
1235 self.class_name = name
1236 self.doc = None
1238 def add_string_const(self, value, identifier = False):
1239 return self.outer_scope.add_string_const(value, identifier)
1241 def lookup(self, name):
1242 if name == "classmethod":
1243 # We don't want to use the builtin classmethod here 'cause it won't do the
1244 # right thing in this scope (as the class memebers aren't still functions).
1245 # Don't want to add a cfunction to this scope 'cause that would mess with
1246 # the type definition, so we just return the right entry.
1247 self.use_utility_code(classmethod_utility_code)
1248 entry = Entry(
1249 "classmethod",
1250 "__Pyx_Method_ClassMethod",
1251 PyrexTypes.CFuncType(
1252 py_object_type,
1253 [PyrexTypes.CFuncTypeArg("", py_object_type, None)], 0, 0))
1254 entry.is_cfunction = 1
1255 return entry
1256 else:
1257 return Scope.lookup(self, name)
1260 class PyClassScope(ClassScope):
1261 # Namespace of a Python class.
1263 # class_dict_cname string C variable holding class dict
1264 # class_obj_cname string C variable holding class object
1266 is_py_class_scope = 1
1268 def declare_var(self, name, type, pos,
1269 cname = None, visibility = 'private', is_cdef = 0):
1270 # Add an entry for a class attribute.
1271 entry = Scope.declare_var(self, name, type, pos,
1272 cname, visibility, is_cdef)
1273 entry.is_pyglobal = 1
1274 return entry
1276 def allocate_temp(self, type):
1277 return self.outer_scope.allocate_temp(type)
1279 def release_temp(self, cname):
1280 self.outer_scope.release_temp(cname)
1282 #def recycle_pending_temps(self):
1283 # self.outer_scope.recycle_pending_temps()
1285 def add_default_value(self, type):
1286 return self.outer_scope.add_default_value(type)
1289 class CClassScope(ClassScope):
1290 # Namespace of an extension type.
1292 # parent_type CClassType
1293 # #typeobj_cname string or None
1294 # #objstruct_cname string
1295 # method_table_cname string
1296 # member_table_cname string
1297 # getset_table_cname string
1298 # has_pyobject_attrs boolean Any PyObject attributes?
1299 # public_attr_entries boolean public/readonly attrs
1300 # property_entries [Entry]
1301 # defined boolean Defined in .pxd file
1302 # implemented boolean Defined in .pyx file
1303 # inherited_var_entries [Entry] Adapted var entries from base class
1305 is_c_class_scope = 1
1307 def __init__(self, name, outer_scope, visibility):
1308 ClassScope.__init__(self, name, outer_scope)
1309 if visibility != 'extern':
1310 self.method_table_cname = outer_scope.mangle(Naming.methtab_prefix, name)
1311 self.member_table_cname = outer_scope.mangle(Naming.memtab_prefix, name)
1312 self.getset_table_cname = outer_scope.mangle(Naming.gstab_prefix, name)
1313 self.has_pyobject_attrs = 0
1314 self.public_attr_entries = []
1315 self.property_entries = []
1316 self.inherited_var_entries = []
1317 self.defined = 0
1318 self.implemented = 0
1320 def needs_gc(self):
1321 # If the type or any of its base types have Python-valued
1322 # C attributes, then it needs to participate in GC.
1323 return self.has_pyobject_attrs or \
1324 (self.parent_type.base_type and \
1325 self.parent_type.base_type.scope.needs_gc())
1327 def declare_var(self, name, type, pos,
1328 cname = None, visibility = 'private', is_cdef = 0):
1329 if is_cdef:
1330 # Add an entry for an attribute.
1331 if self.defined:
1332 error(pos,
1333 "C attributes cannot be added in implementation part of"
1334 " extension type")
1335 if get_special_method_signature(name):
1336 error(pos,
1337 "The name '%s' is reserved for a special method."
1338 % name)
1339 if not cname:
1340 cname = name
1341 entry = self.declare(name, cname, type, pos, visibility)
1342 entry.is_variable = 1
1343 self.var_entries.append(entry)
1344 if type.is_pyobject:
1345 self.has_pyobject_attrs = 1
1346 if visibility not in ('private', 'public', 'readonly'):
1347 error(pos,
1348 "Attribute of extension type cannot be declared %s" % visibility)
1349 if visibility in ('public', 'readonly'):
1350 if type.pymemberdef_typecode:
1351 self.public_attr_entries.append(entry)
1352 if name == "__weakref__":
1353 error(pos, "Special attribute __weakref__ cannot be exposed to Python")
1354 else:
1355 error(pos,
1356 "C attribute of type '%s' cannot be accessed from Python" % type)
1357 if visibility == 'public' and type.is_extension_type:
1358 error(pos,
1359 "Non-generic Python attribute cannot be exposed for writing from Python")
1360 return entry
1361 else:
1362 # Add an entry for a class attribute.
1363 entry = Scope.declare_var(self, name, type, pos,
1364 cname, visibility, is_cdef)
1365 entry.is_member = 1
1366 entry.is_pyglobal = 1 # xxx: is_pyglobal changes behaviour in so many places that
1367 # I keep it in for now. is_member should be enough
1368 # later on
1369 self.namespace_cname = "(PyObject *)%s" % self.parent_type.typeptr_cname
1370 entry.interned_cname = self.intern_identifier(name)
1371 return entry
1374 def declare_pyfunction(self, name, pos):
1375 # Add an entry for a method.
1376 if name in ('__eq__', '__ne__', '__lt__', '__gt__', '__le__', '__ge__'):
1377 error(pos, "Special method %s must be implemented via __richcmp__" % name)
1378 if name == "__new__":
1379 warning(pos, "__new__ method of extension type will change semantics "
1380 "in a future version of Pyrex and Cython. Use __cinit__ instead.")
1381 name = EncodedString("__cinit__")
1382 entry = self.declare_var(name, py_object_type, pos, visibility='extern')
1383 special_sig = get_special_method_signature(name)
1384 if special_sig:
1385 # Special methods get put in the method table with a particular
1386 # signature declared in advance.
1387 entry.signature = special_sig
1388 entry.is_special = 1
1389 else:
1390 entry.signature = pymethod_signature
1391 entry.is_special = 0
1393 self.pyfunc_entries.append(entry)
1394 return entry
1396 def lookup_here(self, name):
1397 if name == "__new__":
1398 name = EncodedString("__cinit__")
1399 return ClassScope.lookup_here(self, name)
1401 def declare_cfunction(self, name, type, pos,
1402 cname = None, visibility = 'private', defining = 0, api = 0, in_pxd = 0):
1403 if get_special_method_signature(name):
1404 error(pos, "Special methods must be declared with 'def', not 'cdef'")
1405 args = type.args
1406 if not args:
1407 error(pos, "C method has no self argument")
1408 elif not args[0].type.same_as(self.parent_type):
1409 error(pos, "Self argument of C method does not match parent type")
1410 entry = self.lookup_here(name)
1411 if entry:
1412 if not entry.is_cfunction:
1413 warning(pos, "'%s' redeclared " % name, 0)
1414 else:
1415 if defining and entry.func_cname:
1416 error(pos, "'%s' already defined" % name)
1417 #print "CClassScope.declare_cfunction: checking signature" ###
1418 if type.same_c_signature_as(entry.type, as_cmethod = 1) and type.nogil == entry.type.nogil:
1419 pass
1420 elif type.compatible_signature_with(entry.type, as_cmethod = 1) and type.nogil == entry.type.nogil:
1421 entry = self.add_cfunction(name, type, pos, cname or name, visibility='ignore')
1422 defining = 1
1423 else:
1424 error(pos, "Signature not compatible with previous declaration")
1425 error(entry.pos, "Previous declaration is here")
1426 else:
1427 if self.defined:
1428 error(pos,
1429 "C method '%s' not previously declared in definition part of"
1430 " extension type" % name)
1431 entry = self.add_cfunction(name, type, pos, cname or name, visibility)
1432 if defining:
1433 entry.func_cname = self.mangle(Naming.func_prefix, name)
1434 return entry
1436 def add_cfunction(self, name, type, pos, cname, visibility):
1437 # Add a cfunction entry without giving it a func_cname.
1438 prev_entry = self.lookup_here(name)
1439 entry = ClassScope.add_cfunction(self, name, type, pos, cname, visibility)
1440 entry.is_cmethod = 1
1441 entry.prev_entry = prev_entry
1442 return entry
1444 def declare_property(self, name, doc, pos):
1445 entry = self.lookup_here(name)
1446 if entry is None:
1447 entry = self.declare(name, name, py_object_type, pos, 'private')
1448 entry.is_property = 1
1449 entry.doc = doc
1450 entry.scope = PropertyScope(name,
1451 outer_scope = self.global_scope(), parent_scope = self)
1452 entry.scope.parent_type = self.parent_type
1453 self.property_entries.append(entry)
1454 return entry
1456 def declare_inherited_c_attributes(self, base_scope):
1457 # Declare entries for all the C attributes of an
1458 # inherited type, with cnames modified appropriately
1459 # to work with this type.
1460 def adapt(cname):
1461 return "%s.%s" % (Naming.obj_base_cname, base_entry.cname)
1462 for base_entry in \
1463 base_scope.inherited_var_entries + base_scope.var_entries:
1464 entry = self.declare(base_entry.name, adapt(base_entry.cname),
1465 base_entry.type, None, 'private')
1466 entry.is_variable = 1
1467 self.inherited_var_entries.append(entry)
1468 for base_entry in base_scope.cfunc_entries:
1469 entry = self.add_cfunction(base_entry.name, base_entry.type,
1470 base_entry.pos, adapt(base_entry.cname), base_entry.visibility)
1471 entry.is_inherited = 1
1473 def allocate_temp(self, type):
1474 return Scope.allocate_temp(self.global_scope(), type)
1476 def release_temp(self, cname):
1477 return Scope.release_temp(self.global_scope(), cname)
1480 class PropertyScope(Scope):
1481 # Scope holding the __get__, __set__ and __del__ methods for
1482 # a property of an extension type.
1484 # parent_type PyExtensionType The type to which the property belongs
1486 def declare_pyfunction(self, name, pos):
1487 # Add an entry for a method.
1488 signature = get_property_accessor_signature(name)
1489 if signature:
1490 entry = self.declare(name, name, py_object_type, pos, 'private')
1491 entry.is_special = 1
1492 entry.signature = signature
1493 return entry
1494 else:
1495 error(pos, "Only __get__, __set__ and __del__ methods allowed "
1496 "in a property declaration")
1497 return None
1500 # Should this go elsewhere (and then get imported)?
1501 #------------------------------------------------------------------------------------
1503 classmethod_utility_code = [
1504 """
1505 #include "descrobject.h"
1506 static PyObject* __Pyx_Method_ClassMethod(PyObject *method); /*proto*/
1507 ""","""
1508 static PyObject* __Pyx_Method_ClassMethod(PyObject *method) {
1509 /* It appears that PyMethodDescr_Type is not anywhere exposed in the Python/C API */
1510 /* if (!PyObject_TypeCheck(method, &PyMethodDescr_Type)) { */
1511 if (strcmp(Py_TYPE(method)->tp_name, "method_descriptor") == 0) { /* cdef classes */
1512 PyMethodDescrObject *descr = (PyMethodDescrObject *)method;
1513 return PyDescr_NewClassMethod(descr->d_type, descr->d_method);
1515 else if (PyMethod_Check(method)) { /* python classes */
1516 return PyClassMethod_New(PyMethod_GET_FUNCTION(method));
1518 else if (PyCFunction_Check(method)) {
1519 return PyClassMethod_New(method);
1521 PyErr_Format(PyExc_TypeError, "Class-level classmethod() can only be called on a method_descriptor or instance method.");
1522 return NULL;
1524 """