12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552 |
- #
- # Symbol Table
- #
- from __future__ import absolute_import
- import re
- import copy
- import operator
- try:
- import __builtin__ as builtins
- except ImportError: # Py3
- import builtins
- from .Errors import warning, error, InternalError
- from .StringEncoding import EncodedString
- from . import Options, Naming
- from . import PyrexTypes
- from .PyrexTypes import py_object_type, unspecified_type
- from .TypeSlots import (
- pyfunction_signature, pymethod_signature, richcmp_special_methods,
- get_special_method_signature, get_property_accessor_signature)
- from . import Future
- from . import Code
- iso_c99_keywords = set(
- ['auto', 'break', 'case', 'char', 'const', 'continue', 'default', 'do',
- 'double', 'else', 'enum', 'extern', 'float', 'for', 'goto', 'if',
- 'int', 'long', 'register', 'return', 'short', 'signed', 'sizeof',
- 'static', 'struct', 'switch', 'typedef', 'union', 'unsigned', 'void',
- 'volatile', 'while',
- '_Bool', '_Complex'', _Imaginary', 'inline', 'restrict'])
- def c_safe_identifier(cname):
- # There are some C limitations on struct entry names.
- if ((cname[:2] == '__' and not (cname.startswith(Naming.pyrex_prefix)
- or cname in ('__weakref__', '__dict__')))
- or cname in iso_c99_keywords):
- cname = Naming.pyrex_prefix + cname
- return cname
- class BufferAux(object):
- writable_needed = False
- def __init__(self, buflocal_nd_var, rcbuf_var):
- self.buflocal_nd_var = buflocal_nd_var
- self.rcbuf_var = rcbuf_var
- def __repr__(self):
- return "<BufferAux %r>" % self.__dict__
- class Entry(object):
- # A symbol table entry in a Scope or ModuleNamespace.
- #
- # name string Python name of entity
- # cname string C name of entity
- # type PyrexType Type of entity
- # doc string Doc string
- # annotation ExprNode PEP 484/526 annotation
- # init string Initial value
- # visibility 'private' or 'public' or 'extern'
- # is_builtin boolean Is an entry in the Python builtins dict
- # is_cglobal boolean Is a C global variable
- # is_pyglobal boolean Is a Python module-level variable
- # or class attribute during
- # class construction
- # is_member boolean Is an assigned class member
- # is_pyclass_attr boolean Is a name in a Python class namespace
- # is_variable boolean Is a variable
- # is_cfunction boolean Is a C function
- # is_cmethod boolean Is a C method of an extension type
- # is_builtin_cmethod boolean Is a C method of a builtin type (implies is_cmethod)
- # is_unbound_cmethod boolean Is an unbound C method of an extension type
- # is_final_cmethod boolean Is non-overridable C method
- # is_inline_cmethod boolean Is inlined C method
- # is_anonymous boolean Is a anonymous pyfunction entry
- # is_type boolean Is a type definition
- # is_cclass boolean Is an extension class
- # is_cpp_class boolean Is a C++ class
- # is_const boolean Is a constant
- # is_property boolean Is a property of an extension type:
- # doc_cname string or None C const holding the docstring
- # getter_cname string C func for getting property
- # setter_cname string C func for setting or deleting property
- # is_self_arg boolean Is the "self" arg of an exttype method
- # is_arg boolean Is the arg of a method
- # is_local boolean Is a local variable
- # in_closure boolean Is referenced in an inner scope
- # in_subscope boolean Belongs to a generator expression scope
- # is_readonly boolean Can't be assigned to
- # func_cname string C func implementing Python func
- # func_modifiers [string] C function modifiers ('inline')
- # pos position Source position where declared
- # namespace_cname string If is_pyglobal, the C variable
- # holding its home namespace
- # pymethdef_cname string PyMethodDef structure
- # signature Signature Arg & return types for Python func
- # as_variable Entry Alternative interpretation of extension
- # type name or builtin C function as a variable
- # xdecref_cleanup boolean Use Py_XDECREF for error cleanup
- # in_cinclude boolean Suppress C declaration code
- # enum_values [Entry] For enum types, list of values
- # qualified_name string "modname.funcname" or "modname.classname"
- # or "modname.classname.funcname"
- # is_declared_generic boolean Is declared as PyObject * even though its
- # type is an extension type
- # as_module None Module scope, if a cimported module
- # is_inherited boolean Is an inherited attribute of an extension type
- # pystring_cname string C name of Python version of string literal
- # is_interned boolean For string const entries, value is interned
- # is_identifier boolean For string const entries, value is an identifier
- # used boolean
- # is_special boolean Is a special method or property accessor
- # of an extension type
- # defined_in_pxd boolean Is defined in a .pxd file (not just declared)
- # api boolean Generate C API for C class or function
- # utility_code string Utility code needed when this entry is used
- #
- # buffer_aux BufferAux or None Extra information needed for buffer variables
- # inline_func_in_pxd boolean Hacky special case for inline function in pxd file.
- # Ideally this should not be necessary.
- # might_overflow boolean In an arithmetic expression that could cause
- # overflow (used for type inference).
- # utility_code_definition For some Cython builtins, the utility code
- # which contains the definition of the entry.
- # Currently only supported for CythonScope entries.
- # error_on_uninitialized Have Control Flow issue an error when this entry is
- # used uninitialized
- # cf_used boolean Entry is used
- # is_fused_specialized boolean Whether this entry of a cdef or def function
- # is a specialization
- # TODO: utility_code and utility_code_definition serves the same purpose...
- inline_func_in_pxd = False
- borrowed = 0
- init = ""
- annotation = None
- visibility = 'private'
- is_builtin = 0
- is_cglobal = 0
- is_pyglobal = 0
- is_member = 0
- is_pyclass_attr = 0
- is_variable = 0
- is_cfunction = 0
- is_cmethod = 0
- is_builtin_cmethod = False
- is_unbound_cmethod = 0
- is_final_cmethod = 0
- is_inline_cmethod = 0
- is_anonymous = 0
- is_type = 0
- is_cclass = 0
- is_cpp_class = 0
- is_const = 0
- is_property = 0
- doc_cname = None
- getter_cname = None
- setter_cname = None
- is_self_arg = 0
- is_arg = 0
- is_local = 0
- in_closure = 0
- from_closure = 0
- in_subscope = 0
- is_declared_generic = 0
- is_readonly = 0
- pyfunc_cname = None
- func_cname = None
- func_modifiers = []
- final_func_cname = None
- doc = None
- as_variable = None
- xdecref_cleanup = 0
- in_cinclude = 0
- as_module = None
- is_inherited = 0
- pystring_cname = None
- is_identifier = 0
- is_interned = 0
- used = 0
- is_special = 0
- defined_in_pxd = 0
- is_implemented = 0
- api = 0
- utility_code = None
- is_overridable = 0
- buffer_aux = None
- prev_entry = None
- might_overflow = 0
- fused_cfunction = None
- is_fused_specialized = False
- utility_code_definition = None
- needs_property = False
- in_with_gil_block = 0
- from_cython_utility_code = None
- error_on_uninitialized = False
- cf_used = True
- outer_entry = None
- def __init__(self, name, cname, type, pos = None, init = None):
- self.name = name
- self.cname = cname
- self.type = type
- self.pos = pos
- self.init = init
- self.overloaded_alternatives = []
- self.cf_assignments = []
- self.cf_references = []
- self.inner_entries = []
- self.defining_entry = self
- def __repr__(self):
- return "%s(<%x>, name=%s, type=%s)" % (type(self).__name__, id(self), self.name, self.type)
- def already_declared_here(self):
- error(self.pos, "Previous declaration is here")
- def redeclared(self, pos):
- error(pos, "'%s' does not match previous declaration" % self.name)
- self.already_declared_here()
- def all_alternatives(self):
- return [self] + self.overloaded_alternatives
- def all_entries(self):
- return [self] + self.inner_entries
- def __lt__(left, right):
- if isinstance(left, Entry) and isinstance(right, Entry):
- return (left.name, left.cname) < (right.name, right.cname)
- else:
- return NotImplemented
- class InnerEntry(Entry):
- """
- An entry in a closure scope that represents the real outer Entry.
- """
- from_closure = True
- def __init__(self, outer_entry, scope):
- Entry.__init__(self, outer_entry.name,
- outer_entry.cname,
- outer_entry.type,
- outer_entry.pos)
- self.outer_entry = outer_entry
- self.scope = scope
- # share state with (outermost) defining entry
- outermost_entry = outer_entry
- while outermost_entry.outer_entry:
- outermost_entry = outermost_entry.outer_entry
- self.defining_entry = outermost_entry
- self.inner_entries = outermost_entry.inner_entries
- self.cf_assignments = outermost_entry.cf_assignments
- self.cf_references = outermost_entry.cf_references
- self.overloaded_alternatives = outermost_entry.overloaded_alternatives
- self.inner_entries.append(self)
- def __getattr__(self, name):
- if name.startswith('__'):
- # we wouldn't have been called if it was there
- raise AttributeError(name)
- return getattr(self.defining_entry, name)
- def all_entries(self):
- return self.defining_entry.all_entries()
- class Scope(object):
- # name string Unqualified name
- # outer_scope Scope or None Enclosing scope
- # entries {string : Entry} Python name to entry, non-types
- # const_entries [Entry] Constant entries
- # type_entries [Entry] Struct/union/enum/typedef/exttype entries
- # sue_entries [Entry] Struct/union/enum entries
- # arg_entries [Entry] Function argument entries
- # var_entries [Entry] User-defined variable entries
- # pyfunc_entries [Entry] Python function entries
- # cfunc_entries [Entry] C function entries
- # c_class_entries [Entry] All extension type entries
- # cname_to_entry {string : Entry} Temp cname to entry mapping
- # return_type PyrexType or None Return type of function owning scope
- # is_builtin_scope boolean Is the builtin scope of Python/Cython
- # is_py_class_scope boolean Is a Python class scope
- # is_c_class_scope boolean Is an extension type scope
- # is_closure_scope boolean Is a closure scope
- # is_passthrough boolean Outer scope is passed directly
- # is_cpp_class_scope boolean Is a C++ class scope
- # is_property_scope boolean Is a extension type property scope
- # scope_prefix string Disambiguator for C names
- # in_cinclude boolean Suppress C declaration code
- # qualified_name string "modname" or "modname.classname"
- # Python strings in this scope
- # nogil boolean In a nogil section
- # directives dict Helper variable for the recursive
- # analysis, contains directive values.
- # is_internal boolean Is only used internally (simpler setup)
- is_builtin_scope = 0
- is_py_class_scope = 0
- is_c_class_scope = 0
- is_closure_scope = 0
- is_genexpr_scope = 0
- is_passthrough = 0
- is_cpp_class_scope = 0
- is_property_scope = 0
- is_module_scope = 0
- is_internal = 0
- scope_prefix = ""
- in_cinclude = 0
- nogil = 0
- fused_to_specific = None
- return_type = None
- def __init__(self, name, outer_scope, parent_scope):
- # The outer_scope is the next scope in the lookup chain.
- # The parent_scope is used to derive the qualified name of this scope.
- self.name = name
- self.outer_scope = outer_scope
- self.parent_scope = parent_scope
- mangled_name = "%d%s_" % (len(name), name.replace('.', '_dot_'))
- qual_scope = self.qualifying_scope()
- if qual_scope:
- self.qualified_name = qual_scope.qualify_name(name)
- self.scope_prefix = qual_scope.scope_prefix + mangled_name
- else:
- self.qualified_name = EncodedString(name)
- self.scope_prefix = mangled_name
- self.entries = {}
- self.subscopes = set()
- self.const_entries = []
- self.type_entries = []
- self.sue_entries = []
- self.arg_entries = []
- self.var_entries = []
- self.pyfunc_entries = []
- self.cfunc_entries = []
- self.c_class_entries = []
- self.defined_c_classes = []
- self.imported_c_classes = {}
- self.cname_to_entry = {}
- self.string_to_entry = {}
- self.identifier_to_entry = {}
- self.num_to_entry = {}
- self.obj_to_entry = {}
- self.buffer_entries = []
- self.lambda_defs = []
- self.id_counters = {}
- def __deepcopy__(self, memo):
- return self
- def merge_in(self, other, merge_unused=True, whitelist=None):
- # Use with care...
- entries = []
- for name, entry in other.entries.items():
- if not whitelist or name in whitelist:
- if entry.used or merge_unused:
- entries.append((name, entry))
- self.entries.update(entries)
- for attr in ('const_entries',
- 'type_entries',
- 'sue_entries',
- 'arg_entries',
- 'var_entries',
- 'pyfunc_entries',
- 'cfunc_entries',
- 'c_class_entries'):
- self_entries = getattr(self, attr)
- names = set(e.name for e in self_entries)
- for entry in getattr(other, attr):
- if (entry.used or merge_unused) and entry.name not in names:
- self_entries.append(entry)
- def __str__(self):
- return "<%s %s>" % (self.__class__.__name__, self.qualified_name)
- def qualifying_scope(self):
- return self.parent_scope
- def mangle(self, prefix, name = None):
- if name:
- return "%s%s%s" % (prefix, self.scope_prefix, name)
- else:
- return self.parent_scope.mangle(prefix, self.name)
- def mangle_internal(self, name):
- # Mangle an internal name so as not to clash with any
- # user-defined name in this scope.
- prefix = "%s%s_" % (Naming.pyrex_prefix, name)
- return self.mangle(prefix)
- #return self.parent_scope.mangle(prefix, self.name)
- def mangle_class_private_name(self, name):
- if self.parent_scope:
- return self.parent_scope.mangle_class_private_name(name)
- return name
- def next_id(self, name=None):
- # Return a cname fragment that is unique for this module
- counters = self.global_scope().id_counters
- try:
- count = counters[name] + 1
- except KeyError:
- count = 0
- counters[name] = count
- if name:
- if not count:
- # unique names don't need a suffix, reoccurrences will get one
- return name
- return '%s%d' % (name, count)
- else:
- return '%d' % count
- def global_scope(self):
- """ Return the module-level scope containing this scope. """
- return self.outer_scope.global_scope()
- def builtin_scope(self):
- """ Return the module-level scope containing this scope. """
- return self.outer_scope.builtin_scope()
- def iter_local_scopes(self):
- yield self
- if self.subscopes:
- for scope in sorted(self.subscopes, key=operator.attrgetter('scope_prefix')):
- yield scope
- def declare(self, name, cname, type, pos, visibility, shadow = 0, is_type = 0, create_wrapper = 0):
- # Create new entry, and add to dictionary if
- # name is not None. Reports a warning if already
- # declared.
- if type.is_buffer and not isinstance(self, LocalScope): # and not is_type:
- error(pos, 'Buffer types only allowed as function local variables')
- if not self.in_cinclude and cname and re.match("^_[_A-Z]+$", cname):
- # See http://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html#Reserved-Names
- warning(pos, "'%s' is a reserved name in C." % cname, -1)
- entries = self.entries
- if name and name in entries and not shadow:
- old_entry = entries[name]
- # Reject redeclared C++ functions only if they have the same type signature.
- cpp_override_allowed = False
- if type.is_cfunction and old_entry.type.is_cfunction and self.is_cpp():
- for alt_entry in old_entry.all_alternatives():
- if type == alt_entry.type:
- if name == '<init>' and not type.args:
- # Cython pre-declares the no-args constructor - allow later user definitions.
- cpp_override_allowed = True
- break
- else:
- cpp_override_allowed = True
- if cpp_override_allowed:
- # C++ function/method overrides with different signatures are ok.
- pass
- elif self.is_cpp_class_scope and entries[name].is_inherited:
- # Likewise ignore inherited classes.
- pass
- elif visibility == 'extern':
- # Silenced outside of "cdef extern" blocks, until we have a safe way to
- # prevent pxd-defined cpdef functions from ending up here.
- warning(pos, "'%s' redeclared " % name, 1 if self.in_cinclude else 0)
- elif visibility != 'ignore':
- error(pos, "'%s' redeclared " % name)
- entries[name].already_declared_here()
- entry = Entry(name, cname, type, pos = pos)
- entry.in_cinclude = self.in_cinclude
- entry.create_wrapper = create_wrapper
- if name:
- entry.qualified_name = self.qualify_name(name)
- # if name in entries and self.is_cpp():
- # entries[name].overloaded_alternatives.append(entry)
- # else:
- # entries[name] = entry
- if not shadow:
- entries[name] = entry
- if type.is_memoryviewslice:
- from . import MemoryView
- entry.init = MemoryView.memslice_entry_init
- entry.scope = self
- entry.visibility = visibility
- return entry
- def qualify_name(self, name):
- return EncodedString("%s.%s" % (self.qualified_name, name))
- def declare_const(self, name, type, value, pos, cname = None, visibility = 'private', api = 0, create_wrapper = 0):
- # Add an entry for a named constant.
- if not cname:
- if self.in_cinclude or (visibility == 'public' or api):
- cname = name
- else:
- cname = self.mangle(Naming.enum_prefix, name)
- entry = self.declare(name, cname, type, pos, visibility, create_wrapper = create_wrapper)
- entry.is_const = 1
- entry.value_node = value
- return entry
- def declare_type(self, name, type, pos,
- cname = None, visibility = 'private', api = 0, defining = 1,
- shadow = 0, template = 0):
- # Add an entry for a type definition.
- if not cname:
- cname = name
- entry = self.declare(name, cname, type, pos, visibility, shadow,
- is_type=True)
- entry.is_type = 1
- entry.api = api
- if defining:
- self.type_entries.append(entry)
- if not template:
- type.entry = entry
- # here we would set as_variable to an object representing this type
- return entry
- def declare_typedef(self, name, base_type, pos, cname = None,
- visibility = 'private', api = 0):
- if not cname:
- if self.in_cinclude or (visibility != 'private' or api):
- cname = name
- else:
- cname = self.mangle(Naming.type_prefix, name)
- try:
- if self.is_cpp_class_scope:
- namespace = self.outer_scope.lookup(self.name).type
- else:
- namespace = None
- type = PyrexTypes.create_typedef_type(name, base_type, cname,
- (visibility == 'extern'),
- namespace)
- except ValueError as e:
- error(pos, e.args[0])
- type = PyrexTypes.error_type
- entry = self.declare_type(name, type, pos, cname,
- visibility = visibility, api = api)
- type.qualified_name = entry.qualified_name
- return entry
- def declare_struct_or_union(self, name, kind, scope,
- typedef_flag, pos, cname = None,
- visibility = 'private', api = 0,
- packed = False):
- # Add an entry for a struct or union definition.
- if not cname:
- if self.in_cinclude or (visibility == 'public' or api):
- cname = name
- else:
- cname = self.mangle(Naming.type_prefix, name)
- entry = self.lookup_here(name)
- if not entry:
- type = PyrexTypes.CStructOrUnionType(
- name, kind, scope, typedef_flag, cname, packed)
- entry = self.declare_type(name, type, pos, cname,
- visibility = visibility, api = api,
- defining = scope is not None)
- self.sue_entries.append(entry)
- type.entry = entry
- else:
- if not (entry.is_type and entry.type.is_struct_or_union
- and entry.type.kind == kind):
- warning(pos, "'%s' redeclared " % name, 0)
- elif scope and entry.type.scope:
- warning(pos, "'%s' already defined (ignoring second definition)" % name, 0)
- else:
- self.check_previous_typedef_flag(entry, typedef_flag, pos)
- self.check_previous_visibility(entry, visibility, pos)
- if scope:
- entry.type.scope = scope
- self.type_entries.append(entry)
- if self.is_cpp_class_scope:
- entry.type.namespace = self.outer_scope.lookup(self.name).type
- return entry
- def declare_cpp_class(self, name, scope,
- pos, cname = None, base_classes = (),
- visibility = 'extern', templates = None):
- if cname is None:
- if self.in_cinclude or (visibility != 'private'):
- cname = name
- else:
- cname = self.mangle(Naming.type_prefix, name)
- base_classes = list(base_classes)
- entry = self.lookup_here(name)
- if not entry:
- type = PyrexTypes.CppClassType(
- name, scope, cname, base_classes, templates = templates)
- entry = self.declare_type(name, type, pos, cname,
- visibility = visibility, defining = scope is not None)
- self.sue_entries.append(entry)
- else:
- if not (entry.is_type and entry.type.is_cpp_class):
- error(pos, "'%s' redeclared " % name)
- entry.already_declared_here()
- return None
- elif scope and entry.type.scope:
- warning(pos, "'%s' already defined (ignoring second definition)" % name, 0)
- else:
- if scope:
- entry.type.scope = scope
- self.type_entries.append(entry)
- if base_classes:
- if entry.type.base_classes and entry.type.base_classes != base_classes:
- error(pos, "Base type does not match previous declaration")
- entry.already_declared_here()
- else:
- entry.type.base_classes = base_classes
- if templates or entry.type.templates:
- if templates != entry.type.templates:
- error(pos, "Template parameters do not match previous declaration")
- entry.already_declared_here()
- def declare_inherited_attributes(entry, base_classes):
- for base_class in base_classes:
- if base_class is PyrexTypes.error_type:
- continue
- if base_class.scope is None:
- error(pos, "Cannot inherit from incomplete type")
- else:
- declare_inherited_attributes(entry, base_class.base_classes)
- entry.type.scope.declare_inherited_cpp_attributes(base_class)
- if scope:
- declare_inherited_attributes(entry, base_classes)
- scope.declare_var(name="this", cname="this", type=PyrexTypes.CPtrType(entry.type), pos=entry.pos)
- if self.is_cpp_class_scope:
- entry.type.namespace = self.outer_scope.lookup(self.name).type
- return entry
- def check_previous_typedef_flag(self, entry, typedef_flag, pos):
- if typedef_flag != entry.type.typedef_flag:
- error(pos, "'%s' previously declared using '%s'" % (
- entry.name, ("cdef", "ctypedef")[entry.type.typedef_flag]))
- def check_previous_visibility(self, entry, visibility, pos):
- if entry.visibility != visibility:
- error(pos, "'%s' previously declared as '%s'" % (
- entry.name, entry.visibility))
- def declare_enum(self, name, pos, cname, typedef_flag,
- visibility = 'private', api = 0, create_wrapper = 0):
- if name:
- if not cname:
- if (self.in_cinclude or visibility == 'public'
- or visibility == 'extern' or api):
- cname = name
- else:
- cname = self.mangle(Naming.type_prefix, name)
- if self.is_cpp_class_scope:
- namespace = self.outer_scope.lookup(self.name).type
- else:
- namespace = None
- type = PyrexTypes.CEnumType(name, cname, typedef_flag, namespace)
- else:
- type = PyrexTypes.c_anon_enum_type
- entry = self.declare_type(name, type, pos, cname = cname,
- visibility = visibility, api = api)
- entry.create_wrapper = create_wrapper
- entry.enum_values = []
- self.sue_entries.append(entry)
- return entry
- def declare_tuple_type(self, pos, components):
- return self.outer_scope.declare_tuple_type(pos, components)
- def declare_var(self, name, type, pos,
- cname = None, visibility = 'private',
- api = 0, in_pxd = 0, is_cdef = 0):
- # Add an entry for a variable.
- if not cname:
- if visibility != 'private' or api:
- cname = name
- else:
- cname = self.mangle(Naming.var_prefix, name)
- if type.is_cpp_class and visibility != 'extern':
- type.check_nullary_constructor(pos)
- entry = self.declare(name, cname, type, pos, visibility)
- entry.is_variable = 1
- if in_pxd and visibility != 'extern':
- entry.defined_in_pxd = 1
- entry.used = 1
- if api:
- entry.api = 1
- entry.used = 1
- return entry
- def declare_builtin(self, name, pos):
- return self.outer_scope.declare_builtin(name, pos)
- def _declare_pyfunction(self, name, pos, visibility='extern', entry=None):
- if entry and not entry.type.is_cfunction:
- error(pos, "'%s' already declared" % name)
- error(entry.pos, "Previous declaration is here")
- entry = self.declare_var(name, py_object_type, pos, visibility=visibility)
- entry.signature = pyfunction_signature
- self.pyfunc_entries.append(entry)
- return entry
- def declare_pyfunction(self, name, pos, allow_redefine=False, visibility='extern'):
- # Add an entry for a Python function.
- entry = self.lookup_here(name)
- if not allow_redefine:
- return self._declare_pyfunction(name, pos, visibility=visibility, entry=entry)
- if entry:
- if entry.type.is_unspecified:
- entry.type = py_object_type
- elif entry.type is not py_object_type:
- return self._declare_pyfunction(name, pos, visibility=visibility, entry=entry)
- else: # declare entry stub
- self.declare_var(name, py_object_type, pos, visibility=visibility)
- entry = self.declare_var(None, py_object_type, pos,
- cname=name, visibility='private')
- entry.name = EncodedString(name)
- entry.qualified_name = self.qualify_name(name)
- entry.signature = pyfunction_signature
- entry.is_anonymous = True
- return entry
- def declare_lambda_function(self, lambda_name, pos):
- # Add an entry for an anonymous Python function.
- func_cname = self.mangle(Naming.lambda_func_prefix + u'funcdef_', lambda_name)
- pymethdef_cname = self.mangle(Naming.lambda_func_prefix + u'methdef_', lambda_name)
- qualified_name = self.qualify_name(lambda_name)
- entry = self.declare(None, func_cname, py_object_type, pos, 'private')
- entry.name = lambda_name
- entry.qualified_name = qualified_name
- entry.pymethdef_cname = pymethdef_cname
- entry.func_cname = func_cname
- entry.signature = pyfunction_signature
- entry.is_anonymous = True
- return entry
- def add_lambda_def(self, def_node):
- self.lambda_defs.append(def_node)
- def register_pyfunction(self, entry):
- self.pyfunc_entries.append(entry)
- def declare_cfunction(self, name, type, pos,
- cname=None, visibility='private', api=0, in_pxd=0,
- defining=0, modifiers=(), utility_code=None, overridable=False):
- # Add an entry for a C function.
- if not cname:
- if visibility != 'private' or api:
- cname = name
- else:
- cname = self.mangle(Naming.func_prefix, name)
- entry = self.lookup_here(name)
- if entry:
- if not in_pxd and visibility != entry.visibility and visibility == 'extern':
- # Previously declared, but now extern => treat this
- # as implementing the function, using the new cname
- defining = True
- visibility = entry.visibility
- entry.cname = cname
- entry.func_cname = cname
- if visibility != 'private' and visibility != entry.visibility:
- warning(pos, "Function '%s' previously declared as '%s', now as '%s'" % (name, entry.visibility, visibility), 1)
- if overridable != entry.is_overridable:
- warning(pos, "Function '%s' previously declared as '%s'" % (
- name, 'cpdef' if overridable else 'cdef'), 1)
- if entry.type.same_as(type):
- # Fix with_gil vs nogil.
- entry.type = entry.type.with_with_gil(type.with_gil)
- else:
- if visibility == 'extern' and entry.visibility == 'extern':
- can_override = False
- if self.is_cpp():
- can_override = True
- elif cname:
- # if all alternatives have different cnames,
- # it's safe to allow signature overrides
- for alt_entry in entry.all_alternatives():
- if not alt_entry.cname or cname == alt_entry.cname:
- break # cname not unique!
- else:
- can_override = True
- if can_override:
- temp = self.add_cfunction(name, type, pos, cname, visibility, modifiers)
- temp.overloaded_alternatives = entry.all_alternatives()
- entry = temp
- else:
- warning(pos, "Function signature does not match previous declaration", 1)
- entry.type = type
- elif not in_pxd and entry.defined_in_pxd and type.compatible_signature_with(entry.type):
- # TODO: check that this was done by a signature optimisation and not a user error.
- #warning(pos, "Function signature does not match previous declaration", 1)
- entry.type = type
- else:
- error(pos, "Function signature does not match previous declaration")
- else:
- entry = self.add_cfunction(name, type, pos, cname, visibility, modifiers)
- entry.func_cname = cname
- entry.is_overridable = overridable
- if in_pxd and visibility != 'extern':
- entry.defined_in_pxd = 1
- if api:
- entry.api = 1
- if not defining and not in_pxd and visibility != 'extern':
- error(pos, "Non-extern C function '%s' declared but not defined" % name)
- if defining:
- entry.is_implemented = True
- if modifiers:
- entry.func_modifiers = modifiers
- if utility_code:
- assert not entry.utility_code, "duplicate utility code definition in entry %s (%s)" % (name, cname)
- entry.utility_code = utility_code
- if overridable:
- # names of cpdef functions can be used as variables and can be assigned to
- var_entry = Entry(name, cname, py_object_type) # FIXME: cname?
- var_entry.qualified_name = self.qualify_name(name)
- var_entry.is_variable = 1
- var_entry.is_pyglobal = 1
- var_entry.scope = entry.scope
- entry.as_variable = var_entry
- type.entry = entry
- return entry
- def add_cfunction(self, name, type, pos, cname, visibility, modifiers, inherited=False):
- # Add a C function entry without giving it a func_cname.
- entry = self.declare(name, cname, type, pos, visibility)
- entry.is_cfunction = 1
- if modifiers:
- entry.func_modifiers = modifiers
- if inherited or type.is_fused:
- self.cfunc_entries.append(entry)
- else:
- # For backwards compatibility reasons, we must keep all non-fused methods
- # before all fused methods, but separately for each type.
- i = len(self.cfunc_entries)
- for cfunc_entry in reversed(self.cfunc_entries):
- if cfunc_entry.is_inherited or not cfunc_entry.type.is_fused:
- break
- i -= 1
- self.cfunc_entries.insert(i, entry)
- return entry
- def find(self, name, pos):
- # Look up name, report error if not found.
- entry = self.lookup(name)
- if entry:
- return entry
- else:
- error(pos, "'%s' is not declared" % name)
- def find_imported_module(self, path, pos):
- # Look up qualified name, must be a module, report error if not found.
- # Path is a list of names.
- scope = self
- for name in path:
- entry = scope.find(name, pos)
- if not entry:
- return None
- if entry.as_module:
- scope = entry.as_module
- else:
- error(pos, "'%s' is not a cimported module" % '.'.join(path))
- return None
- return scope
- def lookup(self, name):
- # Look up name in this scope or an enclosing one.
- # Return None if not found.
- return (self.lookup_here(name)
- or (self.outer_scope and self.outer_scope.lookup(name))
- or None)
- def lookup_here(self, name):
- # Look up in this scope only, return None if not found.
- return self.entries.get(name, None)
- def lookup_target(self, name):
- # Look up name in this scope only. Declare as Python
- # variable if not found.
- entry = self.lookup_here(name)
- if not entry:
- entry = self.declare_var(name, py_object_type, None)
- return entry
- def lookup_type(self, name):
- entry = self.lookup(name)
- if entry and entry.is_type:
- if entry.type.is_fused and self.fused_to_specific:
- return entry.type.specialize(self.fused_to_specific)
- return entry.type
- def lookup_operator(self, operator, operands):
- if operands[0].type.is_cpp_class:
- obj_type = operands[0].type
- method = obj_type.scope.lookup("operator%s" % operator)
- if method is not None:
- arg_types = [arg.type for arg in operands[1:]]
- res = PyrexTypes.best_match([arg.type for arg in operands[1:]],
- method.all_alternatives())
- if res is not None:
- return res
- function = self.lookup("operator%s" % operator)
- function_alternatives = []
- if function is not None:
- function_alternatives = function.all_alternatives()
- # look-up nonmember methods listed within a class
- method_alternatives = []
- if len(operands)==2: # binary operators only
- for n in range(2):
- if operands[n].type.is_cpp_class:
- obj_type = operands[n].type
- method = obj_type.scope.lookup("operator%s" % operator)
- if method is not None:
- method_alternatives += method.all_alternatives()
- if (not method_alternatives) and (not function_alternatives):
- return None
- # select the unique alternatives
- all_alternatives = list(set(method_alternatives + function_alternatives))
- return PyrexTypes.best_match([arg.type for arg in operands],
- all_alternatives)
- def lookup_operator_for_types(self, pos, operator, types):
- from .Nodes import Node
- class FakeOperand(Node):
- pass
- operands = [FakeOperand(pos, type=type) for type in types]
- return self.lookup_operator(operator, operands)
- def use_utility_code(self, new_code):
- self.global_scope().use_utility_code(new_code)
- def use_entry_utility_code(self, entry):
- self.global_scope().use_entry_utility_code(entry)
- def defines_any(self, names):
- # Test whether any of the given names are defined in this scope.
- for name in names:
- if name in self.entries:
- return 1
- return 0
- def defines_any_special(self, names):
- # Test whether any of the given names are defined as special methods in this scope.
- for name in names:
- if name in self.entries and self.entries[name].is_special:
- return 1
- return 0
- def infer_types(self):
- from .TypeInference import get_type_inferer
- get_type_inferer().infer_types(self)
- def is_cpp(self):
- outer = self.outer_scope
- if outer is None:
- return False
- else:
- return outer.is_cpp()
- def add_include_file(self, filename, verbatim_include=None, late=False):
- self.outer_scope.add_include_file(filename, verbatim_include, late)
- class PreImportScope(Scope):
- namespace_cname = Naming.preimport_cname
- def __init__(self):
- Scope.__init__(self, Options.pre_import, None, None)
- def declare_builtin(self, name, pos):
- entry = self.declare(name, name, py_object_type, pos, 'private')
- entry.is_variable = True
- entry.is_pyglobal = True
- return entry
- class BuiltinScope(Scope):
- # The builtin namespace.
- is_builtin_scope = True
- def __init__(self):
- if Options.pre_import is None:
- Scope.__init__(self, "__builtin__", None, None)
- else:
- Scope.__init__(self, "__builtin__", PreImportScope(), None)
- self.type_names = {}
- for name, definition in sorted(self.builtin_entries.items()):
- cname, type = definition
- self.declare_var(name, type, None, cname)
- def lookup(self, name, language_level=None, str_is_str=None):
- # 'language_level' and 'str_is_str' are passed by ModuleScope
- if name == 'str':
- if str_is_str is None:
- str_is_str = language_level in (None, 2)
- if not str_is_str:
- name = 'unicode'
- return Scope.lookup(self, name)
- def declare_builtin(self, name, pos):
- if not hasattr(builtins, name):
- if self.outer_scope is not None:
- return self.outer_scope.declare_builtin(name, pos)
- else:
- if Options.error_on_unknown_names:
- error(pos, "undeclared name not builtin: %s" % name)
- else:
- warning(pos, "undeclared name not builtin: %s" % name, 2)
- def declare_builtin_cfunction(self, name, type, cname, python_equiv=None, utility_code=None):
- # If python_equiv == "*", the Python equivalent has the same name
- # as the entry, otherwise it has the name specified by python_equiv.
- name = EncodedString(name)
- entry = self.declare_cfunction(name, type, None, cname, visibility='extern',
- utility_code=utility_code)
- if python_equiv:
- if python_equiv == "*":
- python_equiv = name
- else:
- python_equiv = EncodedString(python_equiv)
- var_entry = Entry(python_equiv, python_equiv, py_object_type)
- var_entry.qualified_name = self.qualify_name(name)
- var_entry.is_variable = 1
- var_entry.is_builtin = 1
- var_entry.utility_code = utility_code
- var_entry.scope = entry.scope
- entry.as_variable = var_entry
- return entry
- def declare_builtin_type(self, name, cname, utility_code = None, objstruct_cname = None):
- name = EncodedString(name)
- type = PyrexTypes.BuiltinObjectType(name, cname, objstruct_cname)
- scope = CClassScope(name, outer_scope=None, visibility='extern')
- scope.directives = {}
- if name == 'bool':
- type.is_final_type = True
- type.set_scope(scope)
- self.type_names[name] = 1
- entry = self.declare_type(name, type, None, visibility='extern')
- entry.utility_code = utility_code
- var_entry = Entry(name = entry.name,
- type = self.lookup('type').type, # make sure "type" is the first type declared...
- pos = entry.pos,
- cname = entry.type.typeptr_cname)
- var_entry.qualified_name = self.qualify_name(name)
- var_entry.is_variable = 1
- var_entry.is_cglobal = 1
- var_entry.is_readonly = 1
- var_entry.is_builtin = 1
- var_entry.utility_code = utility_code
- var_entry.scope = self
- if Options.cache_builtins:
- var_entry.is_const = True
- entry.as_variable = var_entry
- return type
- def builtin_scope(self):
- return self
- builtin_entries = {
- "type": ["((PyObject*)&PyType_Type)", py_object_type],
- "bool": ["((PyObject*)&PyBool_Type)", py_object_type],
- "int": ["((PyObject*)&PyInt_Type)", py_object_type],
- "long": ["((PyObject*)&PyLong_Type)", py_object_type],
- "float": ["((PyObject*)&PyFloat_Type)", py_object_type],
- "complex":["((PyObject*)&PyComplex_Type)", py_object_type],
- "bytes": ["((PyObject*)&PyBytes_Type)", py_object_type],
- "bytearray": ["((PyObject*)&PyByteArray_Type)", py_object_type],
- "str": ["((PyObject*)&PyString_Type)", py_object_type],
- "unicode":["((PyObject*)&PyUnicode_Type)", py_object_type],
- "tuple": ["((PyObject*)&PyTuple_Type)", py_object_type],
- "list": ["((PyObject*)&PyList_Type)", py_object_type],
- "dict": ["((PyObject*)&PyDict_Type)", py_object_type],
- "set": ["((PyObject*)&PySet_Type)", py_object_type],
- "frozenset": ["((PyObject*)&PyFrozenSet_Type)", py_object_type],
- "slice": ["((PyObject*)&PySlice_Type)", py_object_type],
- # "file": ["((PyObject*)&PyFile_Type)", py_object_type], # not in Py3
- "None": ["Py_None", py_object_type],
- "False": ["Py_False", py_object_type],
- "True": ["Py_True", py_object_type],
- }
- const_counter = 1 # As a temporary solution for compiling code in pxds
- class ModuleScope(Scope):
- # module_name string Python name of the module
- # module_cname string C name of Python module object
- # #module_dict_cname string C name of module dict object
- # method_table_cname string C name of method table
- # doc string Module doc string
- # doc_cname string C name of module doc string
- # utility_code_list [UtilityCode] Queuing utility codes for forwarding to Code.py
- # c_includes {key: IncludeCode} C headers or verbatim code to be generated
- # See process_include() for more documentation
- # string_to_entry {string : Entry} Map string const to entry
- # identifier_to_entry {string : Entry} Map identifier string const to entry
- # context Context
- # parent_module Scope Parent in the import namespace
- # module_entries {string : Entry} For cimport statements
- # type_names {string : 1} Set of type names (used during parsing)
- # included_files [string] Cython sources included with 'include'
- # pxd_file_loaded boolean Corresponding .pxd file has been processed
- # cimported_modules [ModuleScope] Modules imported with cimport
- # types_imported {PyrexType} Set of types for which import code generated
- # has_import_star boolean Module contains import *
- # cpp boolean Compiling a C++ file
- # is_cython_builtin boolean Is this the Cython builtin scope (or a child scope)
- # is_package boolean Is this a package module? (__init__)
- is_module_scope = 1
- has_import_star = 0
- is_cython_builtin = 0
- old_style_globals = 0
- def __init__(self, name, parent_module, context):
- from . import Builtin
- self.parent_module = parent_module
- outer_scope = Builtin.builtin_scope
- Scope.__init__(self, name, outer_scope, parent_module)
- if name == "__init__":
- # Treat Spam/__init__.pyx specially, so that when Python loads
- # Spam/__init__.so, initSpam() is defined.
- self.module_name = parent_module.module_name
- self.is_package = True
- else:
- self.module_name = name
- self.is_package = False
- self.module_name = EncodedString(self.module_name)
- self.context = context
- self.module_cname = Naming.module_cname
- self.module_dict_cname = Naming.moddict_cname
- self.method_table_cname = Naming.methtable_cname
- self.doc = ""
- self.doc_cname = Naming.moddoc_cname
- self.utility_code_list = []
- self.module_entries = {}
- self.c_includes = {}
- self.type_names = dict(outer_scope.type_names)
- self.pxd_file_loaded = 0
- self.cimported_modules = []
- self.types_imported = set()
- self.included_files = []
- self.has_extern_class = 0
- self.cached_builtins = []
- self.undeclared_cached_builtins = []
- self.namespace_cname = self.module_cname
- self._cached_tuple_types = {}
- for var_name in ['__builtins__', '__name__', '__file__', '__doc__', '__path__',
- '__spec__', '__loader__', '__package__', '__cached__']:
- self.declare_var(EncodedString(var_name), py_object_type, None)
- self.process_include(Code.IncludeCode("Python.h", initial=True))
- def qualifying_scope(self):
- return self.parent_module
- def global_scope(self):
- return self
- def lookup(self, name, language_level=None, str_is_str=None):
- entry = self.lookup_here(name)
- if entry is not None:
- return entry
- if language_level is None:
- language_level = self.context.language_level if self.context is not None else 3
- if str_is_str is None:
- str_is_str = language_level == 2 or (
- self.context is not None and Future.unicode_literals not in self.context.future_directives)
- return self.outer_scope.lookup(name, language_level=language_level, str_is_str=str_is_str)
- def declare_tuple_type(self, pos, components):
- components = tuple(components)
- try:
- ttype = self._cached_tuple_types[components]
- except KeyError:
- ttype = self._cached_tuple_types[components] = PyrexTypes.c_tuple_type(components)
- cname = ttype.cname
- entry = self.lookup_here(cname)
- if not entry:
- scope = StructOrUnionScope(cname)
- for ix, component in enumerate(components):
- scope.declare_var(name="f%s" % ix, type=component, pos=pos)
- struct_entry = self.declare_struct_or_union(
- cname + '_struct', 'struct', scope, typedef_flag=True, pos=pos, cname=cname)
- self.type_entries.remove(struct_entry)
- ttype.struct_entry = struct_entry
- entry = self.declare_type(cname, ttype, pos, cname)
- ttype.entry = entry
- return entry
- def declare_builtin(self, name, pos):
- if not hasattr(builtins, name) \
- and name not in Code.non_portable_builtins_map \
- and name not in Code.uncachable_builtins:
- if self.has_import_star:
- entry = self.declare_var(name, py_object_type, pos)
- return entry
- else:
- if Options.error_on_unknown_names:
- error(pos, "undeclared name not builtin: %s" % name)
- else:
- warning(pos, "undeclared name not builtin: %s" % name, 2)
- # unknown - assume it's builtin and look it up at runtime
- entry = self.declare(name, None, py_object_type, pos, 'private')
- entry.is_builtin = 1
- return entry
- if Options.cache_builtins:
- for entry in self.cached_builtins:
- if entry.name == name:
- return entry
- if name == 'globals' and not self.old_style_globals:
- return self.outer_scope.lookup('__Pyx_Globals')
- else:
- entry = self.declare(None, None, py_object_type, pos, 'private')
- if Options.cache_builtins and name not in Code.uncachable_builtins:
- entry.is_builtin = 1
- entry.is_const = 1 # cached
- entry.name = name
- entry.cname = Naming.builtin_prefix + name
- self.cached_builtins.append(entry)
- self.undeclared_cached_builtins.append(entry)
- else:
- entry.is_builtin = 1
- entry.name = name
- entry.qualified_name = self.builtin_scope().qualify_name(name)
- return entry
- def find_module(self, module_name, pos, relative_level=-1):
- # Find a module in the import namespace, interpreting
- # relative imports relative to this module's parent.
- # Finds and parses the module's .pxd file if the module
- # has not been referenced before.
- relative_to = None
- absolute_fallback = False
- if relative_level is not None and relative_level > 0:
- # explicit relative cimport
- # error of going beyond top-level is handled in cimport node
- relative_to = self
- while relative_level > 0 and relative_to:
- relative_to = relative_to.parent_module
- relative_level -= 1
- elif relative_level != 0:
- # -1 or None: try relative cimport first, then absolute
- relative_to = self.parent_module
- absolute_fallback = True
- module_scope = self.global_scope()
- return module_scope.context.find_module(
- module_name, relative_to=relative_to, pos=pos, absolute_fallback=absolute_fallback)
- def find_submodule(self, name):
- # Find and return scope for a submodule of this module,
- # creating a new empty one if necessary. Doesn't parse .pxd.
- if '.' in name:
- name, submodule = name.split('.', 1)
- else:
- submodule = None
- scope = self.lookup_submodule(name)
- if not scope:
- scope = ModuleScope(name, parent_module=self, context=self.context)
- self.module_entries[name] = scope
- if submodule:
- scope = scope.find_submodule(submodule)
- return scope
- def lookup_submodule(self, name):
- # Return scope for submodule of this module, or None.
- if '.' in name:
- name, submodule = name.split('.', 1)
- else:
- submodule = None
- module = self.module_entries.get(name, None)
- if submodule and module is not None:
- module = module.lookup_submodule(submodule)
- return module
- def add_include_file(self, filename, verbatim_include=None, late=False):
- """
- Add `filename` as include file. Add `verbatim_include` as
- verbatim text in the C file.
- Both `filename` and `verbatim_include` can be `None` or empty.
- """
- inc = Code.IncludeCode(filename, verbatim_include, late=late)
- self.process_include(inc)
- def process_include(self, inc):
- """
- Add `inc`, which is an instance of `IncludeCode`, to this
- `ModuleScope`. This either adds a new element to the
- `c_includes` dict or it updates an existing entry.
- In detail: the values of the dict `self.c_includes` are
- instances of `IncludeCode` containing the code to be put in the
- generated C file. The keys of the dict are needed to ensure
- uniqueness in two ways: if an include file is specified in
- multiple "cdef extern" blocks, only one `#include` statement is
- generated. Second, the same include might occur multiple times
- if we find it through multiple "cimport" paths. So we use the
- generated code (of the form `#include "header.h"`) as dict key.
- If verbatim code does not belong to any include file (i.e. it
- was put in a `cdef extern from *` block), then we use a unique
- dict key: namely, the `sortkey()`.
- One `IncludeCode` object can contain multiple pieces of C code:
- one optional "main piece" for the include file and several other
- pieces for the verbatim code. The `IncludeCode.dict_update`
- method merges the pieces of two different `IncludeCode` objects
- if needed.
- """
- key = inc.mainpiece()
- if key is None:
- key = inc.sortkey()
- inc.dict_update(self.c_includes, key)
- inc = self.c_includes[key]
- def add_imported_module(self, scope):
- if scope not in self.cimported_modules:
- for inc in scope.c_includes.values():
- self.process_include(inc)
- self.cimported_modules.append(scope)
- for m in scope.cimported_modules:
- self.add_imported_module(m)
- def add_imported_entry(self, name, entry, pos):
- if entry.is_pyglobal:
- # Allow cimports to follow imports.
- entry.is_variable = True
- if entry not in self.entries:
- self.entries[name] = entry
- else:
- warning(pos, "'%s' redeclared " % name, 0)
- def declare_module(self, name, scope, pos):
- # Declare a cimported module. This is represented as a
- # Python module-level variable entry with a module
- # scope attached to it. Reports an error and returns
- # None if previously declared as something else.
- entry = self.lookup_here(name)
- if entry:
- if entry.is_pyglobal and entry.as_module is scope:
- return entry # Already declared as the same module
- if not (entry.is_pyglobal and not entry.as_module):
- # SAGE -- I put this here so Pyrex
- # cimport's work across directories.
- # Currently it tries to multiply define
- # every module appearing in an import list.
- # It shouldn't be an error for a module
- # name to appear again, and indeed the generated
- # code compiles fine.
- return entry
- else:
- entry = self.declare_var(name, py_object_type, pos)
- entry.is_variable = 0
- entry.as_module = scope
- self.add_imported_module(scope)
- return entry
- def declare_var(self, name, type, pos,
- cname = None, visibility = 'private',
- api = 0, in_pxd = 0, is_cdef = 0):
- # Add an entry for a global variable. If it is a Python
- # object type, and not declared with cdef, it will live
- # in the module dictionary, otherwise it will be a C
- # global variable.
- if not visibility in ('private', 'public', 'extern'):
- error(pos, "Module-level variable cannot be declared %s" % visibility)
- if not is_cdef:
- if type is unspecified_type:
- type = py_object_type
- if not (type.is_pyobject and not type.is_extension_type):
- raise InternalError(
- "Non-cdef global variable is not a generic Python object")
- if not cname:
- defining = not in_pxd
- if visibility == 'extern' or (visibility == 'public' and defining):
- cname = name
- else:
- cname = self.mangle(Naming.var_prefix, name)
- entry = self.lookup_here(name)
- if entry and entry.defined_in_pxd:
- #if visibility != 'private' and visibility != entry.visibility:
- # warning(pos, "Variable '%s' previously declared as '%s'" % (name, entry.visibility), 1)
- if not entry.type.same_as(type):
- if visibility == 'extern' and entry.visibility == 'extern':
- warning(pos, "Variable '%s' type does not match previous declaration" % name, 1)
- entry.type = type
- #else:
- # error(pos, "Variable '%s' type does not match previous declaration" % name)
- if entry.visibility != "private":
- mangled_cname = self.mangle(Naming.var_prefix, name)
- if entry.cname == mangled_cname:
- cname = name
- entry.cname = name
- if not entry.is_implemented:
- entry.is_implemented = True
- return entry
- entry = Scope.declare_var(self, name, type, pos,
- cname=cname, visibility=visibility,
- api=api, in_pxd=in_pxd, is_cdef=is_cdef)
- if is_cdef:
- entry.is_cglobal = 1
- if entry.type.declaration_value:
- entry.init = entry.type.declaration_value
- self.var_entries.append(entry)
- else:
- entry.is_pyglobal = 1
- if Options.cimport_from_pyx:
- entry.used = 1
- return entry
- def declare_cfunction(self, name, type, pos,
- cname=None, visibility='private', api=0, in_pxd=0,
- defining=0, modifiers=(), utility_code=None, overridable=False):
- if not defining and 'inline' in modifiers:
- # TODO(github/1736): Make this an error.
- warning(pos, "Declarations should not be declared inline.", 1)
- # Add an entry for a C function.
- if not cname:
- if visibility == 'extern' or (visibility == 'public' and defining):
- cname = name
- else:
- cname = self.mangle(Naming.func_prefix, name)
- if visibility == 'extern' and type.optional_arg_count:
- error(pos, "Extern functions cannot have default arguments values.")
- entry = self.lookup_here(name)
- if entry and entry.defined_in_pxd:
- if entry.visibility != "private":
- mangled_cname = self.mangle(Naming.var_prefix, name)
- if entry.cname == mangled_cname:
- cname = name
- entry.cname = cname
- entry.func_cname = cname
- entry = Scope.declare_cfunction(
- self, name, type, pos,
- cname=cname, visibility=visibility, api=api, in_pxd=in_pxd,
- defining=defining, modifiers=modifiers, utility_code=utility_code,
- overridable=overridable)
- return entry
- def declare_global(self, name, pos):
- entry = self.lookup_here(name)
- if not entry:
- self.declare_var(name, py_object_type, pos)
- def use_utility_code(self, new_code):
- if new_code is not None:
- self.utility_code_list.append(new_code)
- def use_entry_utility_code(self, entry):
- if entry is None:
- return
- if entry.utility_code:
- self.utility_code_list.append(entry.utility_code)
- if entry.utility_code_definition:
- self.utility_code_list.append(entry.utility_code_definition)
- def declare_c_class(self, name, pos, defining=0, implementing=0,
- module_name=None, base_type=None, objstruct_cname=None,
- typeobj_cname=None, typeptr_cname=None, visibility='private',
- typedef_flag=0, api=0, check_size=None,
- buffer_defaults=None, shadow=0):
- # If this is a non-extern typedef class, expose the typedef, but use
- # the non-typedef struct internally to avoid needing forward
- # declarations for anonymous structs.
- if typedef_flag and visibility != 'extern':
- if not (visibility == 'public' or api):
- warning(pos, "ctypedef only valid for 'extern' , 'public', and 'api'", 2)
- objtypedef_cname = objstruct_cname
- typedef_flag = 0
- else:
- objtypedef_cname = None
- #
- # Look for previous declaration as a type
- #
- entry = self.lookup_here(name)
- if entry and not shadow:
- type = entry.type
- if not (entry.is_type and type.is_extension_type):
- entry = None # Will cause redeclaration and produce an error
- else:
- scope = type.scope
- if typedef_flag and (not scope or scope.defined):
- self.check_previous_typedef_flag(entry, typedef_flag, pos)
- if (scope and scope.defined) or (base_type and type.base_type):
- if base_type and base_type is not type.base_type:
- error(pos, "Base type does not match previous declaration")
- if base_type and not type.base_type:
- type.base_type = base_type
- #
- # Make a new entry if needed
- #
- if not entry or shadow:
- type = PyrexTypes.PyExtensionType(
- name, typedef_flag, base_type, visibility == 'extern', check_size=check_size)
- type.pos = pos
- type.buffer_defaults = buffer_defaults
- if objtypedef_cname is not None:
- type.objtypedef_cname = objtypedef_cname
- if visibility == 'extern':
- type.module_name = module_name
- else:
- type.module_name = self.qualified_name
- if typeptr_cname:
- type.typeptr_cname = typeptr_cname
- else:
- type.typeptr_cname = self.mangle(Naming.typeptr_prefix, name)
- entry = self.declare_type(name, type, pos, visibility = visibility,
- defining = 0, shadow = shadow)
- entry.is_cclass = True
- if objstruct_cname:
- type.objstruct_cname = objstruct_cname
- elif not entry.in_cinclude:
- type.objstruct_cname = self.mangle(Naming.objstruct_prefix, name)
- else:
- error(entry.pos,
- "Object name required for 'public' or 'extern' C class")
- self.attach_var_entry_to_c_class(entry)
- self.c_class_entries.append(entry)
- #
- # Check for re-definition and create scope if needed
- #
- if not type.scope:
- if defining or implementing:
- scope = CClassScope(name = name, outer_scope = self,
- visibility = visibility)
- scope.directives = self.directives.copy()
- if base_type and base_type.scope:
- scope.declare_inherited_c_attributes(base_type.scope)
- type.set_scope(scope)
- self.type_entries.append(entry)
- else:
- if defining and type.scope.defined:
- error(pos, "C class '%s' already defined" % name)
- elif implementing and type.scope.implemented:
- error(pos, "C class '%s' already implemented" % name)
- #
- # Fill in options, checking for compatibility with any previous declaration
- #
- if defining:
- entry.defined_in_pxd = 1
- if implementing: # So that filenames in runtime exceptions refer to
- entry.pos = pos # the .pyx file and not the .pxd file
- if visibility != 'private' and entry.visibility != visibility:
- error(pos, "Class '%s' previously declared as '%s'"
- % (name, entry.visibility))
- if api:
- entry.api = 1
- if objstruct_cname:
- if type.objstruct_cname and type.objstruct_cname != objstruct_cname:
- error(pos, "Object struct name differs from previous declaration")
- type.objstruct_cname = objstruct_cname
- if typeobj_cname:
- if type.typeobj_cname and type.typeobj_cname != typeobj_cname:
- error(pos, "Type object name differs from previous declaration")
- type.typeobj_cname = typeobj_cname
- if self.directives.get('final'):
- entry.type.is_final_type = True
- # cdef classes are always exported, but we need to set it to
- # distinguish between unused Cython utility code extension classes
- entry.used = True
- #
- # Return new or existing entry
- #
- return entry
- def allocate_vtable_names(self, entry):
- # If extension type has a vtable, allocate vtable struct and
- # slot names for it.
- type = entry.type
- if type.base_type and type.base_type.vtabslot_cname:
- #print "...allocating vtabslot_cname because base type has one" ###
- type.vtabslot_cname = "%s.%s" % (
- Naming.obj_base_cname, type.base_type.vtabslot_cname)
- elif type.scope and type.scope.cfunc_entries:
- # one special case here: when inheriting from builtin
- # types, the methods may also be built-in, in which
- # case they won't need a vtable
- entry_count = len(type.scope.cfunc_entries)
- base_type = type.base_type
- while base_type:
- # FIXME: this will break if we ever get non-inherited C methods
- if not base_type.scope or entry_count > len(base_type.scope.cfunc_entries):
- break
- if base_type.is_builtin_type:
- # builtin base type defines all methods => no vtable needed
- return
- base_type = base_type.base_type
- #print "...allocating vtabslot_cname because there are C methods" ###
- type.vtabslot_cname = Naming.vtabslot_cname
- if type.vtabslot_cname:
- #print "...allocating other vtable related cnames" ###
- type.vtabstruct_cname = self.mangle(Naming.vtabstruct_prefix, entry.name)
- type.vtabptr_cname = self.mangle(Naming.vtabptr_prefix, entry.name)
- def check_c_classes_pxd(self):
- # Performs post-analysis checking and finishing up of extension types
- # being implemented in this module. This is called only for the .pxd.
- #
- # Checks all extension types declared in this scope to
- # make sure that:
- #
- # * The extension type is fully declared
- #
- # Also allocates a name for the vtable if needed.
- #
- for entry in self.c_class_entries:
- # Check defined
- if not entry.type.scope:
- error(entry.pos, "C class '%s' is declared but not defined" % entry.name)
- def check_c_class(self, entry):
- type = entry.type
- name = entry.name
- visibility = entry.visibility
- # Check defined
- if not type.scope:
- error(entry.pos, "C class '%s' is declared but not defined" % name)
- # Generate typeobj_cname
- if visibility != 'extern' and not type.typeobj_cname:
- type.typeobj_cname = self.mangle(Naming.typeobj_prefix, name)
- ## Generate typeptr_cname
- #type.typeptr_cname = self.mangle(Naming.typeptr_prefix, name)
- # Check C methods defined
- if type.scope:
- for method_entry in type.scope.cfunc_entries:
- if not method_entry.is_inherited and not method_entry.func_cname:
- error(method_entry.pos, "C method '%s' is declared but not defined" %
- method_entry.name)
- # Allocate vtable name if necessary
- if type.vtabslot_cname:
- #print "ModuleScope.check_c_classes: allocating vtable cname for", self ###
- type.vtable_cname = self.mangle(Naming.vtable_prefix, entry.name)
- def check_c_classes(self):
- # Performs post-analysis checking and finishing up of extension types
- # being implemented in this module. This is called only for the main
- # .pyx file scope, not for cimported .pxd scopes.
- #
- # Checks all extension types declared in this scope to
- # make sure that:
- #
- # * The extension type is implemented
- # * All required object and type names have been specified or generated
- # * All non-inherited C methods are implemented
- #
- # Also allocates a name for the vtable if needed.
- #
- debug_check_c_classes = 0
- if debug_check_c_classes:
- print("Scope.check_c_classes: checking scope " + self.qualified_name)
- for entry in self.c_class_entries:
- if debug_check_c_classes:
- print("...entry %s %s" % (entry.name, entry))
- print("......type = ", entry.type)
- print("......visibility = ", entry.visibility)
- self.check_c_class(entry)
- def check_c_functions(self):
- # Performs post-analysis checking making sure all
- # defined c functions are actually implemented.
- for name, entry in self.entries.items():
- if entry.is_cfunction:
- if (entry.defined_in_pxd
- and entry.scope is self
- and entry.visibility != 'extern'
- and not entry.in_cinclude
- and not entry.is_implemented):
- error(entry.pos, "Non-extern C function '%s' declared but not defined" % name)
- def attach_var_entry_to_c_class(self, entry):
- # The name of an extension class has to serve as both a type
- # name and a variable name holding the type object. It is
- # represented in the symbol table by a type entry with a
- # variable entry attached to it. For the variable entry,
- # we use a read-only C global variable whose name is an
- # expression that refers to the type object.
- from . import Builtin
- var_entry = Entry(name = entry.name,
- type = Builtin.type_type,
- pos = entry.pos,
- cname = entry.type.typeptr_cname)
- var_entry.qualified_name = entry.qualified_name
- var_entry.is_variable = 1
- var_entry.is_cglobal = 1
- var_entry.is_readonly = 1
- var_entry.scope = entry.scope
- entry.as_variable = var_entry
- def is_cpp(self):
- return self.cpp
- def infer_types(self):
- from .TypeInference import PyObjectTypeInferer
- PyObjectTypeInferer().infer_types(self)
- class LocalScope(Scope):
- # Does the function have a 'with gil:' block?
- has_with_gil_block = False
- # Transient attribute, used for symbol table variable declarations
- _in_with_gil_block = False
- def __init__(self, name, outer_scope, parent_scope = None):
- if parent_scope is None:
- parent_scope = outer_scope
- Scope.__init__(self, name, outer_scope, parent_scope)
- def mangle(self, prefix, name):
- return prefix + name
- def declare_arg(self, name, type, pos):
- # Add an entry for an argument of a function.
- cname = self.mangle(Naming.var_prefix, name)
- entry = self.declare(name, cname, type, pos, 'private')
- entry.is_variable = 1
- if type.is_pyobject:
- entry.init = "0"
- entry.is_arg = 1
- #entry.borrowed = 1 # Not using borrowed arg refs for now
- self.arg_entries.append(entry)
- return entry
- def declare_var(self, name, type, pos,
- cname = None, visibility = 'private',
- api = 0, in_pxd = 0, is_cdef = 0):
- # Add an entry for a local variable.
- if visibility in ('public', 'readonly'):
- error(pos, "Local variable cannot be declared %s" % visibility)
- entry = Scope.declare_var(self, name, type, pos,
- cname=cname, visibility=visibility,
- api=api, in_pxd=in_pxd, is_cdef=is_cdef)
- if entry.type.declaration_value:
- entry.init = entry.type.declaration_value
- entry.is_local = 1
- entry.in_with_gil_block = self._in_with_gil_block
- self.var_entries.append(entry)
- return entry
- def declare_global(self, name, pos):
- # Pull entry from global scope into local scope.
- if self.lookup_here(name):
- warning(pos, "'%s' redeclared ", 0)
- else:
- entry = self.global_scope().lookup_target(name)
- self.entries[name] = entry
- def declare_nonlocal(self, name, pos):
- # Pull entry from outer scope into local scope
- orig_entry = self.lookup_here(name)
- if orig_entry and orig_entry.scope is self and not orig_entry.from_closure:
- error(pos, "'%s' redeclared as nonlocal" % name)
- orig_entry.already_declared_here()
- else:
- entry = self.lookup(name)
- if entry is None or not entry.from_closure:
- error(pos, "no binding for nonlocal '%s' found" % name)
- def lookup(self, name):
- # Look up name in this scope or an enclosing one.
- # Return None if not found.
- entry = Scope.lookup(self, name)
- if entry is not None:
- entry_scope = entry.scope
- while entry_scope.is_genexpr_scope:
- entry_scope = entry_scope.outer_scope
- if entry_scope is not self and entry_scope.is_closure_scope:
- if hasattr(entry.scope, "scope_class"):
- raise InternalError("lookup() after scope class created.")
- # The actual c fragment for the different scopes differs
- # on the outside and inside, so we make a new entry
- entry.in_closure = True
- inner_entry = InnerEntry(entry, self)
- inner_entry.is_variable = True
- self.entries[name] = inner_entry
- return inner_entry
- return entry
- def mangle_closure_cnames(self, outer_scope_cname):
- for scope in self.iter_local_scopes():
- for entry in scope.entries.values():
- if entry.from_closure:
- cname = entry.outer_entry.cname
- if self.is_passthrough:
- entry.cname = cname
- else:
- if cname.startswith(Naming.cur_scope_cname):
- cname = cname[len(Naming.cur_scope_cname)+2:]
- entry.cname = "%s->%s" % (outer_scope_cname, cname)
- elif entry.in_closure:
- entry.original_cname = entry.cname
- entry.cname = "%s->%s" % (Naming.cur_scope_cname, entry.cname)
- class GeneratorExpressionScope(Scope):
- """Scope for generator expressions and comprehensions. As opposed
- to generators, these can be easily inlined in some cases, so all
- we really need is a scope that holds the loop variable(s).
- """
- is_genexpr_scope = True
- def __init__(self, outer_scope):
- parent_scope = outer_scope
- # TODO: also ignore class scopes?
- while parent_scope.is_genexpr_scope:
- parent_scope = parent_scope.parent_scope
- name = parent_scope.global_scope().next_id(Naming.genexpr_id_ref)
- Scope.__init__(self, name, outer_scope, parent_scope)
- self.directives = outer_scope.directives
- self.genexp_prefix = "%s%d%s" % (Naming.pyrex_prefix, len(name), name)
- # Class/ExtType scopes are filled at class creation time, i.e. from the
- # module init function or surrounding function.
- while outer_scope.is_genexpr_scope or outer_scope.is_c_class_scope or outer_scope.is_py_class_scope:
- outer_scope = outer_scope.outer_scope
- self.var_entries = outer_scope.var_entries # keep declarations outside
- outer_scope.subscopes.add(self)
- def mangle(self, prefix, name):
- return '%s%s' % (self.genexp_prefix, self.parent_scope.mangle(prefix, name))
- def declare_var(self, name, type, pos,
- cname = None, visibility = 'private',
- api = 0, in_pxd = 0, is_cdef = True):
- if type is unspecified_type:
- # if the outer scope defines a type for this variable, inherit it
- outer_entry = self.outer_scope.lookup(name)
- if outer_entry and outer_entry.is_variable:
- type = outer_entry.type # may still be 'unspecified_type' !
- # the parent scope needs to generate code for the variable, but
- # this scope must hold its name exclusively
- cname = '%s%s' % (self.genexp_prefix, self.parent_scope.mangle(Naming.var_prefix, name or self.next_id()))
- entry = self.declare(name, cname, type, pos, visibility)
- entry.is_variable = True
- if self.parent_scope.is_module_scope:
- entry.is_cglobal = True
- else:
- entry.is_local = True
- entry.in_subscope = True
- self.var_entries.append(entry)
- self.entries[name] = entry
- return entry
- def declare_pyfunction(self, name, pos, allow_redefine=False):
- return self.outer_scope.declare_pyfunction(
- name, pos, allow_redefine)
- def declare_lambda_function(self, func_cname, pos):
- return self.outer_scope.declare_lambda_function(func_cname, pos)
- def add_lambda_def(self, def_node):
- return self.outer_scope.add_lambda_def(def_node)
- class ClosureScope(LocalScope):
- is_closure_scope = True
- def __init__(self, name, scope_name, outer_scope, parent_scope=None):
- LocalScope.__init__(self, name, outer_scope, parent_scope)
- self.closure_cname = "%s%s" % (Naming.closure_scope_prefix, scope_name)
- # def mangle_closure_cnames(self, scope_var):
- # for entry in self.entries.values() + self.temp_entries:
- # entry.in_closure = 1
- # LocalScope.mangle_closure_cnames(self, scope_var)
- # def mangle(self, prefix, name):
- # return "%s->%s" % (self.cur_scope_cname, name)
- # return "%s->%s" % (self.closure_cname, name)
- def declare_pyfunction(self, name, pos, allow_redefine=False):
- return LocalScope.declare_pyfunction(self, name, pos, allow_redefine, visibility='private')
- class StructOrUnionScope(Scope):
- # Namespace of a C struct or union.
- def __init__(self, name="?"):
- Scope.__init__(self, name, None, None)
- def declare_var(self, name, type, pos,
- cname = None, visibility = 'private',
- api = 0, in_pxd = 0, is_cdef = 0,
- allow_pyobject=False, allow_memoryview=False):
- # Add an entry for an attribute.
- if not cname:
- cname = name
- if visibility == 'private':
- cname = c_safe_identifier(cname)
- if type.is_cfunction:
- type = PyrexTypes.CPtrType(type)
- entry = self.declare(name, cname, type, pos, visibility)
- entry.is_variable = 1
- self.var_entries.append(entry)
- if type.is_pyobject and not allow_pyobject:
- error(pos, "C struct/union member cannot be a Python object")
- elif type.is_memoryviewslice and not allow_memoryview:
- # Memory views wrap their buffer owner as a Python object.
- error(pos, "C struct/union member cannot be a memory view")
- if visibility != 'private':
- error(pos, "C struct/union member cannot be declared %s" % visibility)
- return entry
- def declare_cfunction(self, name, type, pos,
- cname=None, visibility='private', api=0, in_pxd=0,
- defining=0, modifiers=(), overridable=False): # currently no utility code ...
- if overridable:
- error(pos, "C struct/union member cannot be declared 'cpdef'")
- return self.declare_var(name, type, pos,
- cname=cname, visibility=visibility)
- class ClassScope(Scope):
- # Abstract base class for namespace of
- # Python class or extension type.
- #
- # class_name string Python name of the class
- # scope_prefix string Additional prefix for names
- # declared in the class
- # doc string or None Doc string
- def __init__(self, name, outer_scope):
- Scope.__init__(self, name, outer_scope, outer_scope)
- self.class_name = name
- self.doc = None
- def lookup(self, name):
- entry = Scope.lookup(self, name)
- if entry:
- return entry
- if name == "classmethod":
- # We don't want to use the builtin classmethod here 'cause it won't do the
- # right thing in this scope (as the class members aren't still functions).
- # Don't want to add a cfunction to this scope 'cause that would mess with
- # the type definition, so we just return the right entry.
- entry = Entry(
- "classmethod",
- "__Pyx_Method_ClassMethod",
- PyrexTypes.CFuncType(
- py_object_type,
- [PyrexTypes.CFuncTypeArg("", py_object_type, None)], 0, 0))
- entry.utility_code_definition = Code.UtilityCode.load_cached("ClassMethod", "CythonFunction.c")
- self.use_entry_utility_code(entry)
- entry.is_cfunction = 1
- return entry
- class PyClassScope(ClassScope):
- # Namespace of a Python class.
- #
- # class_obj_cname string C variable holding class object
- is_py_class_scope = 1
- def mangle_class_private_name(self, name):
- return self.mangle_special_name(name)
- def mangle_special_name(self, name):
- if name and name.startswith('__') and not name.endswith('__'):
- name = EncodedString('_%s%s' % (self.class_name.lstrip('_'), name))
- return name
- def lookup_here(self, name):
- name = self.mangle_special_name(name)
- return ClassScope.lookup_here(self, name)
- def declare_var(self, name, type, pos,
- cname = None, visibility = 'private',
- api = 0, in_pxd = 0, is_cdef = 0):
- name = self.mangle_special_name(name)
- if type is unspecified_type:
- type = py_object_type
- # Add an entry for a class attribute.
- entry = Scope.declare_var(self, name, type, pos,
- cname=cname, visibility=visibility,
- api=api, in_pxd=in_pxd, is_cdef=is_cdef)
- entry.is_pyglobal = 1
- entry.is_pyclass_attr = 1
- return entry
- def declare_nonlocal(self, name, pos):
- # Pull entry from outer scope into local scope
- orig_entry = self.lookup_here(name)
- if orig_entry and orig_entry.scope is self and not orig_entry.from_closure:
- error(pos, "'%s' redeclared as nonlocal" % name)
- orig_entry.already_declared_here()
- else:
- entry = self.lookup(name)
- if entry is None:
- error(pos, "no binding for nonlocal '%s' found" % name)
- else:
- # FIXME: this works, but it's unclear if it's the
- # right thing to do
- self.entries[name] = entry
- def declare_global(self, name, pos):
- # Pull entry from global scope into local scope.
- if self.lookup_here(name):
- warning(pos, "'%s' redeclared ", 0)
- else:
- entry = self.global_scope().lookup_target(name)
- self.entries[name] = entry
- def add_default_value(self, type):
- return self.outer_scope.add_default_value(type)
- class CClassScope(ClassScope):
- # Namespace of an extension type.
- #
- # parent_type CClassType
- # #typeobj_cname string or None
- # #objstruct_cname string
- # method_table_cname string
- # getset_table_cname string
- # has_pyobject_attrs boolean Any PyObject attributes?
- # has_memoryview_attrs boolean Any memory view attributes?
- # has_cpp_class_attrs boolean Any (non-pointer) C++ attributes?
- # has_cyclic_pyobject_attrs boolean Any PyObject attributes that may need GC?
- # property_entries [Entry]
- # defined boolean Defined in .pxd file
- # implemented boolean Defined in .pyx file
- # inherited_var_entries [Entry] Adapted var entries from base class
- is_c_class_scope = 1
- is_closure_class_scope = False
- has_pyobject_attrs = False
- has_memoryview_attrs = False
- has_cpp_class_attrs = False
- has_cyclic_pyobject_attrs = False
- defined = False
- implemented = False
- def __init__(self, name, outer_scope, visibility):
- ClassScope.__init__(self, name, outer_scope)
- if visibility != 'extern':
- self.method_table_cname = outer_scope.mangle(Naming.methtab_prefix, name)
- self.getset_table_cname = outer_scope.mangle(Naming.gstab_prefix, name)
- self.property_entries = []
- self.inherited_var_entries = []
- def needs_gc(self):
- # If the type or any of its base types have Python-valued
- # C attributes, then it needs to participate in GC.
- if self.has_cyclic_pyobject_attrs and not self.directives.get('no_gc', False):
- return True
- base_type = self.parent_type.base_type
- if base_type and base_type.scope is not None:
- return base_type.scope.needs_gc()
- elif self.parent_type.is_builtin_type:
- return not self.parent_type.is_gc_simple
- return False
- def needs_tp_clear(self):
- """
- Do we need to generate an implementation for the tp_clear slot? Can
- be disabled to keep references for the __dealloc__ cleanup function.
- """
- return self.needs_gc() and not self.directives.get('no_gc_clear', False)
- def get_refcounted_entries(self, include_weakref=False,
- include_gc_simple=True):
- py_attrs = []
- py_buffers = []
- memoryview_slices = []
- for entry in self.var_entries:
- if entry.type.is_pyobject:
- if include_weakref or (self.is_closure_class_scope or entry.name != "__weakref__"):
- if include_gc_simple or not entry.type.is_gc_simple:
- py_attrs.append(entry)
- elif entry.type == PyrexTypes.c_py_buffer_type:
- py_buffers.append(entry)
- elif entry.type.is_memoryviewslice:
- memoryview_slices.append(entry)
- have_entries = py_attrs or py_buffers or memoryview_slices
- return have_entries, (py_attrs, py_buffers, memoryview_slices)
- def declare_var(self, name, type, pos,
- cname = None, visibility = 'private',
- api = 0, in_pxd = 0, is_cdef = 0):
- if is_cdef:
- # Add an entry for an attribute.
- if self.defined:
- error(pos,
- "C attributes cannot be added in implementation part of"
- " extension type defined in a pxd")
- if not self.is_closure_class_scope and get_special_method_signature(name):
- error(pos,
- "The name '%s' is reserved for a special method."
- % name)
- if not cname:
- cname = name
- if visibility == 'private':
- cname = c_safe_identifier(cname)
- if type.is_cpp_class and visibility != 'extern':
- type.check_nullary_constructor(pos)
- self.use_utility_code(Code.UtilityCode("#include <new>"))
- entry = self.declare(name, cname, type, pos, visibility)
- entry.is_variable = 1
- self.var_entries.append(entry)
- if type.is_memoryviewslice:
- self.has_memoryview_attrs = True
- elif type.is_cpp_class:
- self.has_cpp_class_attrs = True
- elif type.is_pyobject and (self.is_closure_class_scope or name != '__weakref__'):
- self.has_pyobject_attrs = True
- if (not type.is_builtin_type
- or not type.scope or type.scope.needs_gc()):
- self.has_cyclic_pyobject_attrs = True
- if visibility not in ('private', 'public', 'readonly'):
- error(pos,
- "Attribute of extension type cannot be declared %s" % visibility)
- if visibility in ('public', 'readonly'):
- # If the field is an external typedef, we cannot be sure about the type,
- # so do conversion ourself rather than rely on the CPython mechanism (through
- # a property; made in AnalyseDeclarationsTransform).
- entry.needs_property = True
- if not self.is_closure_class_scope and name == "__weakref__":
- error(pos, "Special attribute __weakref__ cannot be exposed to Python")
- if not (type.is_pyobject or type.can_coerce_to_pyobject(self)):
- # we're not testing for coercion *from* Python here - that would fail later
- error(pos, "C attribute of type '%s' cannot be accessed from Python" % type)
- else:
- entry.needs_property = False
- return entry
- else:
- if type is unspecified_type:
- type = py_object_type
- # Add an entry for a class attribute.
- entry = Scope.declare_var(self, name, type, pos,
- cname=cname, visibility=visibility,
- api=api, in_pxd=in_pxd, is_cdef=is_cdef)
- entry.is_member = 1
- entry.is_pyglobal = 1 # xxx: is_pyglobal changes behaviour in so many places that
- # I keep it in for now. is_member should be enough
- # later on
- self.namespace_cname = "(PyObject *)%s" % self.parent_type.typeptr_cname
- return entry
- def declare_pyfunction(self, name, pos, allow_redefine=False):
- # Add an entry for a method.
- if name in richcmp_special_methods:
- if self.lookup_here('__richcmp__'):
- error(pos, "Cannot define both % and __richcmp__" % name)
- elif name == '__richcmp__':
- for n in richcmp_special_methods:
- if self.lookup_here(n):
- error(pos, "Cannot define both % and __richcmp__" % n)
- if name == "__new__":
- error(pos, "__new__ method of extension type will change semantics "
- "in a future version of Pyrex and Cython. Use __cinit__ instead.")
- entry = self.declare_var(name, py_object_type, pos,
- visibility='extern')
- special_sig = get_special_method_signature(name)
- if special_sig:
- # Special methods get put in the method table with a particular
- # signature declared in advance.
- entry.signature = special_sig
- entry.is_special = 1
- else:
- entry.signature = pymethod_signature
- entry.is_special = 0
- self.pyfunc_entries.append(entry)
- return entry
- def lookup_here(self, name):
- if not self.is_closure_class_scope and name == "__new__":
- name = EncodedString("__cinit__")
- entry = ClassScope.lookup_here(self, name)
- if entry and entry.is_builtin_cmethod:
- if not self.parent_type.is_builtin_type:
- # For subtypes of builtin types, we can only return
- # optimised C methods if the type if final.
- # Otherwise, subtypes may choose to override the
- # method, but the optimisation would prevent the
- # subtype method from being called.
- if not self.parent_type.is_final_type:
- return None
- return entry
- def declare_cfunction(self, name, type, pos,
- cname=None, visibility='private', api=0, in_pxd=0,
- defining=0, modifiers=(), utility_code=None, overridable=False):
- if get_special_method_signature(name) and not self.parent_type.is_builtin_type:
- error(pos, "Special methods must be declared with 'def', not 'cdef'")
- args = type.args
- if not type.is_static_method:
- if not args:
- error(pos, "C method has no self argument")
- elif not self.parent_type.assignable_from(args[0].type):
- error(pos, "Self argument (%s) of C method '%s' does not match parent type (%s)" %
- (args[0].type, name, self.parent_type))
- entry = self.lookup_here(name)
- if cname is None:
- cname = c_safe_identifier(name)
- if entry:
- if not entry.is_cfunction:
- warning(pos, "'%s' redeclared " % name, 0)
- else:
- if defining and entry.func_cname:
- error(pos, "'%s' already defined" % name)
- #print "CClassScope.declare_cfunction: checking signature" ###
- if entry.is_final_cmethod and entry.is_inherited:
- error(pos, "Overriding final methods is not allowed")
- elif type.same_c_signature_as(entry.type, as_cmethod = 1) and type.nogil == entry.type.nogil:
- # Fix with_gil vs nogil.
- entry.type = entry.type.with_with_gil(type.with_gil)
- elif type.compatible_signature_with(entry.type, as_cmethod = 1) and type.nogil == entry.type.nogil:
- if (self.defined and not in_pxd
- and not type.same_c_signature_as_resolved_type(entry.type, as_cmethod = 1, as_pxd_definition = 1)):
- # TODO(robertwb): Make this an error.
- warning(pos,
- "Compatible but non-identical C method '%s' not redeclared "
- "in definition part of extension type '%s'. "
- "This may cause incorrect vtables to be generated." % (
- name, self.class_name), 2)
- warning(entry.pos, "Previous declaration is here", 2)
- entry = self.add_cfunction(name, type, pos, cname, visibility='ignore', modifiers=modifiers)
- else:
- error(pos, "Signature not compatible with previous declaration")
- error(entry.pos, "Previous declaration is here")
- else:
- if self.defined:
- error(pos,
- "C method '%s' not previously declared in definition part of"
- " extension type '%s'" % (name, self.class_name))
- entry = self.add_cfunction(name, type, pos, cname, visibility, modifiers)
- if defining:
- entry.func_cname = self.mangle(Naming.func_prefix, name)
- entry.utility_code = utility_code
- type.entry = entry
- if u'inline' in modifiers:
- entry.is_inline_cmethod = True
- if (self.parent_type.is_final_type or entry.is_inline_cmethod or
- self.directives.get('final')):
- entry.is_final_cmethod = True
- entry.final_func_cname = entry.func_cname
- return entry
- def add_cfunction(self, name, type, pos, cname, visibility, modifiers, inherited=False):
- # Add a cfunction entry without giving it a func_cname.
- prev_entry = self.lookup_here(name)
- entry = ClassScope.add_cfunction(self, name, type, pos, cname,
- visibility, modifiers, inherited=inherited)
- entry.is_cmethod = 1
- entry.prev_entry = prev_entry
- return entry
- def declare_builtin_cfunction(self, name, type, cname, utility_code = None):
- # overridden methods of builtin types still have their Python
- # equivalent that must be accessible to support bound methods
- name = EncodedString(name)
- entry = self.declare_cfunction(name, type, None, cname, visibility='extern',
- utility_code=utility_code)
- var_entry = Entry(name, name, py_object_type)
- var_entry.qualified_name = name
- var_entry.is_variable = 1
- var_entry.is_builtin = 1
- var_entry.utility_code = utility_code
- var_entry.scope = entry.scope
- entry.as_variable = var_entry
- return entry
- def declare_property(self, name, doc, pos):
- entry = self.lookup_here(name)
- if entry is None:
- entry = self.declare(name, name, py_object_type, pos, 'private')
- entry.is_property = 1
- entry.doc = doc
- entry.scope = PropertyScope(name,
- outer_scope = self.global_scope(), parent_scope = self)
- entry.scope.parent_type = self.parent_type
- self.property_entries.append(entry)
- return entry
- def declare_inherited_c_attributes(self, base_scope):
- # Declare entries for all the C attributes of an
- # inherited type, with cnames modified appropriately
- # to work with this type.
- def adapt(cname):
- return "%s.%s" % (Naming.obj_base_cname, base_entry.cname)
- entries = base_scope.inherited_var_entries + base_scope.var_entries
- for base_entry in entries:
- entry = self.declare(
- base_entry.name, adapt(base_entry.cname),
- base_entry.type, None, 'private')
- entry.is_variable = 1
- self.inherited_var_entries.append(entry)
- # If the class defined in a pxd, specific entries have not been added.
- # Ensure now that the parent (base) scope has specific entries
- # Iterate over a copy as get_all_specialized_function_types() will mutate
- for base_entry in base_scope.cfunc_entries[:]:
- if base_entry.type.is_fused:
- base_entry.type.get_all_specialized_function_types()
- for base_entry in base_scope.cfunc_entries:
- cname = base_entry.cname
- var_entry = base_entry.as_variable
- is_builtin = var_entry and var_entry.is_builtin
- if not is_builtin:
- cname = adapt(cname)
- entry = self.add_cfunction(base_entry.name, base_entry.type,
- base_entry.pos, cname,
- base_entry.visibility, base_entry.func_modifiers, inherited=True)
- entry.is_inherited = 1
- if base_entry.is_final_cmethod:
- entry.is_final_cmethod = True
- entry.is_inline_cmethod = base_entry.is_inline_cmethod
- if (self.parent_scope == base_scope.parent_scope or
- entry.is_inline_cmethod):
- entry.final_func_cname = base_entry.final_func_cname
- if is_builtin:
- entry.is_builtin_cmethod = True
- entry.as_variable = var_entry
- if base_entry.utility_code:
- entry.utility_code = base_entry.utility_code
- class CppClassScope(Scope):
- # Namespace of a C++ class.
- is_cpp_class_scope = 1
- default_constructor = None
- type = None
- def __init__(self, name, outer_scope, templates=None):
- Scope.__init__(self, name, outer_scope, None)
- self.directives = outer_scope.directives
- self.inherited_var_entries = []
- if templates is not None:
- for T in templates:
- template_entry = self.declare(
- T, T, PyrexTypes.TemplatePlaceholderType(T), None, 'extern')
- template_entry.is_type = 1
- def declare_var(self, name, type, pos,
- cname = None, visibility = 'extern',
- api = 0, in_pxd = 0, is_cdef = 0, defining = 0):
- # Add an entry for an attribute.
- if not cname:
- cname = name
- entry = self.lookup_here(name)
- if defining and entry is not None:
- if entry.type.same_as(type):
- # Fix with_gil vs nogil.
- entry.type = entry.type.with_with_gil(type.with_gil)
- elif type.is_cfunction and type.compatible_signature_with(entry.type):
- entry.type = type
- else:
- error(pos, "Function signature does not match previous declaration")
- else:
- entry = self.declare(name, cname, type, pos, visibility)
- entry.is_variable = 1
- if type.is_cfunction and self.type:
- if not self.type.get_fused_types():
- entry.func_cname = "%s::%s" % (self.type.empty_declaration_code(), cname)
- if name != "this" and (defining or name != "<init>"):
- self.var_entries.append(entry)
- return entry
- def declare_cfunction(self, name, type, pos,
- cname=None, visibility='extern', api=0, in_pxd=0,
- defining=0, modifiers=(), utility_code=None, overridable=False):
- class_name = self.name.split('::')[-1]
- if name in (class_name, '__init__') and cname is None:
- cname = "%s__init__%s" % (Naming.func_prefix, class_name)
- name = '<init>'
- type.return_type = PyrexTypes.CVoidType()
- # This is called by the actual constructor, but need to support
- # arguments that cannot by called by value.
- type.original_args = type.args
- def maybe_ref(arg):
- if arg.type.is_cpp_class and not arg.type.is_reference:
- return PyrexTypes.CFuncTypeArg(
- arg.name, PyrexTypes.c_ref_type(arg.type), arg.pos)
- else:
- return arg
- type.args = [maybe_ref(arg) for arg in type.args]
- elif name == '__dealloc__' and cname is None:
- cname = "%s__dealloc__%s" % (Naming.func_prefix, class_name)
- name = '<del>'
- type.return_type = PyrexTypes.CVoidType()
- if name in ('<init>', '<del>') and type.nogil:
- for base in self.type.base_classes:
- base_entry = base.scope.lookup(name)
- if base_entry and not base_entry.type.nogil:
- error(pos, "Constructor cannot be called without GIL unless all base constructors can also be called without GIL")
- error(base_entry.pos, "Base constructor defined here.")
- prev_entry = self.lookup_here(name)
- entry = self.declare_var(name, type, pos,
- defining=defining,
- cname=cname, visibility=visibility)
- if prev_entry and not defining:
- entry.overloaded_alternatives = prev_entry.all_alternatives()
- entry.utility_code = utility_code
- type.entry = entry
- return entry
- def declare_inherited_cpp_attributes(self, base_class):
- base_scope = base_class.scope
- template_type = base_class
- while getattr(template_type, 'template_type', None):
- template_type = template_type.template_type
- if getattr(template_type, 'templates', None):
- base_templates = [T.name for T in template_type.templates]
- else:
- base_templates = ()
- # Declare entries for all the C++ attributes of an
- # inherited type, with cnames modified appropriately
- # to work with this type.
- for base_entry in \
- base_scope.inherited_var_entries + base_scope.var_entries:
- #constructor/destructor is not inherited
- if base_entry.name in ("<init>", "<del>"):
- continue
- #print base_entry.name, self.entries
- if base_entry.name in self.entries:
- base_entry.name # FIXME: is there anything to do in this case?
- entry = self.declare(base_entry.name, base_entry.cname,
- base_entry.type, None, 'extern')
- entry.is_variable = 1
- entry.is_inherited = 1
- self.inherited_var_entries.append(entry)
- for base_entry in base_scope.cfunc_entries:
- entry = self.declare_cfunction(base_entry.name, base_entry.type,
- base_entry.pos, base_entry.cname,
- base_entry.visibility, api=0,
- modifiers=base_entry.func_modifiers,
- utility_code=base_entry.utility_code)
- entry.is_inherited = 1
- for base_entry in base_scope.type_entries:
- if base_entry.name not in base_templates:
- entry = self.declare_type(base_entry.name, base_entry.type,
- base_entry.pos, base_entry.cname,
- base_entry.visibility)
- entry.is_inherited = 1
- def specialize(self, values, type_entry):
- scope = CppClassScope(self.name, self.outer_scope)
- scope.type = type_entry
- for entry in self.entries.values():
- if entry.is_type:
- scope.declare_type(entry.name,
- entry.type.specialize(values),
- entry.pos,
- entry.cname,
- template=1)
- elif entry.type.is_cfunction:
- for e in entry.all_alternatives():
- scope.declare_cfunction(e.name,
- e.type.specialize(values),
- e.pos,
- e.cname,
- utility_code=e.utility_code)
- else:
- scope.declare_var(entry.name,
- entry.type.specialize(values),
- entry.pos,
- entry.cname,
- entry.visibility)
- return scope
- class PropertyScope(Scope):
- # Scope holding the __get__, __set__ and __del__ methods for
- # a property of an extension type.
- #
- # parent_type PyExtensionType The type to which the property belongs
- is_property_scope = 1
- def declare_pyfunction(self, name, pos, allow_redefine=False):
- # Add an entry for a method.
- signature = get_property_accessor_signature(name)
- if signature:
- entry = self.declare(name, name, py_object_type, pos, 'private')
- entry.is_special = 1
- entry.signature = signature
- return entry
- else:
- error(pos, "Only __get__, __set__ and __del__ methods allowed "
- "in a property declaration")
- return None
- class CConstScope(Scope):
- def __init__(self, const_base_type_scope):
- Scope.__init__(
- self,
- 'const_' + const_base_type_scope.name,
- const_base_type_scope.outer_scope,
- const_base_type_scope.parent_scope)
- self.const_base_type_scope = const_base_type_scope
- def lookup_here(self, name):
- entry = self.const_base_type_scope.lookup_here(name)
- if entry is not None:
- entry = copy.copy(entry)
- entry.type = PyrexTypes.c_const_type(entry.type)
- return entry
- class TemplateScope(Scope):
- def __init__(self, name, outer_scope):
- Scope.__init__(self, name, outer_scope, None)
- self.directives = outer_scope.directives
|