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