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