ParseTreeTransforms.py 133 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441
  1. from __future__ import absolute_import
  2. import cython
  3. cython.declare(PyrexTypes=object, Naming=object, ExprNodes=object, Nodes=object,
  4. Options=object, UtilNodes=object, LetNode=object,
  5. LetRefNode=object, TreeFragment=object, EncodedString=object,
  6. error=object, warning=object, copy=object, _unicode=object)
  7. import copy
  8. import hashlib
  9. from . import PyrexTypes
  10. from . import Naming
  11. from . import ExprNodes
  12. from . import Nodes
  13. from . import Options
  14. from . import Builtin
  15. from . import Errors
  16. from .Visitor import VisitorTransform, TreeVisitor
  17. from .Visitor import CythonTransform, EnvTransform, ScopeTrackingTransform
  18. from .UtilNodes import LetNode, LetRefNode
  19. from .TreeFragment import TreeFragment
  20. from .StringEncoding import EncodedString, _unicode
  21. from .Errors import error, warning, CompileError, InternalError
  22. from .Code import UtilityCode
  23. class NameNodeCollector(TreeVisitor):
  24. """Collect all NameNodes of a (sub-)tree in the ``name_nodes``
  25. attribute.
  26. """
  27. def __init__(self):
  28. super(NameNodeCollector, self).__init__()
  29. self.name_nodes = []
  30. def visit_NameNode(self, node):
  31. self.name_nodes.append(node)
  32. def visit_Node(self, node):
  33. self._visitchildren(node, None)
  34. class SkipDeclarations(object):
  35. """
  36. Variable and function declarations can often have a deep tree structure,
  37. and yet most transformations don't need to descend to this depth.
  38. Declaration nodes are removed after AnalyseDeclarationsTransform, so there
  39. is no need to use this for transformations after that point.
  40. """
  41. def visit_CTypeDefNode(self, node):
  42. return node
  43. def visit_CVarDefNode(self, node):
  44. return node
  45. def visit_CDeclaratorNode(self, node):
  46. return node
  47. def visit_CBaseTypeNode(self, node):
  48. return node
  49. def visit_CEnumDefNode(self, node):
  50. return node
  51. def visit_CStructOrUnionDefNode(self, node):
  52. return node
  53. class NormalizeTree(CythonTransform):
  54. """
  55. This transform fixes up a few things after parsing
  56. in order to make the parse tree more suitable for
  57. transforms.
  58. a) After parsing, blocks with only one statement will
  59. be represented by that statement, not by a StatListNode.
  60. When doing transforms this is annoying and inconsistent,
  61. as one cannot in general remove a statement in a consistent
  62. way and so on. This transform wraps any single statements
  63. in a StatListNode containing a single statement.
  64. b) The PassStatNode is a noop and serves no purpose beyond
  65. plugging such one-statement blocks; i.e., once parsed a
  66. ` "pass" can just as well be represented using an empty
  67. StatListNode. This means less special cases to worry about
  68. in subsequent transforms (one always checks to see if a
  69. StatListNode has no children to see if the block is empty).
  70. """
  71. def __init__(self, context):
  72. super(NormalizeTree, self).__init__(context)
  73. self.is_in_statlist = False
  74. self.is_in_expr = False
  75. def visit_ExprNode(self, node):
  76. stacktmp = self.is_in_expr
  77. self.is_in_expr = True
  78. self.visitchildren(node)
  79. self.is_in_expr = stacktmp
  80. return node
  81. def visit_StatNode(self, node, is_listcontainer=False):
  82. stacktmp = self.is_in_statlist
  83. self.is_in_statlist = is_listcontainer
  84. self.visitchildren(node)
  85. self.is_in_statlist = stacktmp
  86. if not self.is_in_statlist and not self.is_in_expr:
  87. return Nodes.StatListNode(pos=node.pos, stats=[node])
  88. else:
  89. return node
  90. def visit_StatListNode(self, node):
  91. self.is_in_statlist = True
  92. self.visitchildren(node)
  93. self.is_in_statlist = False
  94. return node
  95. def visit_ParallelAssignmentNode(self, node):
  96. return self.visit_StatNode(node, True)
  97. def visit_CEnumDefNode(self, node):
  98. return self.visit_StatNode(node, True)
  99. def visit_CStructOrUnionDefNode(self, node):
  100. return self.visit_StatNode(node, True)
  101. def visit_PassStatNode(self, node):
  102. """Eliminate PassStatNode"""
  103. if not self.is_in_statlist:
  104. return Nodes.StatListNode(pos=node.pos, stats=[])
  105. else:
  106. return []
  107. def visit_ExprStatNode(self, node):
  108. """Eliminate useless string literals"""
  109. if node.expr.is_string_literal:
  110. return self.visit_PassStatNode(node)
  111. else:
  112. return self.visit_StatNode(node)
  113. def visit_CDeclaratorNode(self, node):
  114. return node
  115. class PostParseError(CompileError): pass
  116. # error strings checked by unit tests, so define them
  117. ERR_CDEF_INCLASS = 'Cannot assign default value to fields in cdef classes, structs or unions'
  118. ERR_BUF_DEFAULTS = 'Invalid buffer defaults specification (see docs)'
  119. ERR_INVALID_SPECIALATTR_TYPE = 'Special attributes must not have a type declared'
  120. class PostParse(ScopeTrackingTransform):
  121. """
  122. Basic interpretation of the parse tree, as well as validity
  123. checking that can be done on a very basic level on the parse
  124. tree (while still not being a problem with the basic syntax,
  125. as such).
  126. Specifically:
  127. - Default values to cdef assignments are turned into single
  128. assignments following the declaration (everywhere but in class
  129. bodies, where they raise a compile error)
  130. - Interpret some node structures into Python runtime values.
  131. Some nodes take compile-time arguments (currently:
  132. TemplatedTypeNode[args] and __cythonbufferdefaults__ = {args}),
  133. which should be interpreted. This happens in a general way
  134. and other steps should be taken to ensure validity.
  135. Type arguments cannot be interpreted in this way.
  136. - For __cythonbufferdefaults__ the arguments are checked for
  137. validity.
  138. TemplatedTypeNode has its directives interpreted:
  139. Any first positional argument goes into the "dtype" attribute,
  140. any "ndim" keyword argument goes into the "ndim" attribute and
  141. so on. Also it is checked that the directive combination is valid.
  142. - __cythonbufferdefaults__ attributes are parsed and put into the
  143. type information.
  144. Note: Currently Parsing.py does a lot of interpretation and
  145. reorganization that can be refactored into this transform
  146. if a more pure Abstract Syntax Tree is wanted.
  147. """
  148. def __init__(self, context):
  149. super(PostParse, self).__init__(context)
  150. self.specialattribute_handlers = {
  151. '__cythonbufferdefaults__' : self.handle_bufferdefaults
  152. }
  153. def visit_LambdaNode(self, node):
  154. # unpack a lambda expression into the corresponding DefNode
  155. collector = YieldNodeCollector()
  156. collector.visitchildren(node.result_expr)
  157. if collector.has_yield or collector.has_await or isinstance(node.result_expr, ExprNodes.YieldExprNode):
  158. body = Nodes.ExprStatNode(
  159. node.result_expr.pos, expr=node.result_expr)
  160. else:
  161. body = Nodes.ReturnStatNode(
  162. node.result_expr.pos, value=node.result_expr)
  163. node.def_node = Nodes.DefNode(
  164. node.pos, name=node.name,
  165. args=node.args, star_arg=node.star_arg,
  166. starstar_arg=node.starstar_arg,
  167. body=body, doc=None)
  168. self.visitchildren(node)
  169. return node
  170. def visit_GeneratorExpressionNode(self, node):
  171. # unpack a generator expression into the corresponding DefNode
  172. collector = YieldNodeCollector()
  173. collector.visitchildren(node.loop)
  174. node.def_node = Nodes.DefNode(
  175. node.pos, name=node.name, doc=None,
  176. args=[], star_arg=None, starstar_arg=None,
  177. body=node.loop, is_async_def=collector.has_await)
  178. self.visitchildren(node)
  179. return node
  180. def visit_ComprehensionNode(self, node):
  181. # enforce local scope also in Py2 for async generators (seriously, that's a Py3.6 feature...)
  182. if not node.has_local_scope:
  183. collector = YieldNodeCollector()
  184. collector.visitchildren(node.loop)
  185. if collector.has_await:
  186. node.has_local_scope = True
  187. self.visitchildren(node)
  188. return node
  189. # cdef variables
  190. def handle_bufferdefaults(self, decl):
  191. if not isinstance(decl.default, ExprNodes.DictNode):
  192. raise PostParseError(decl.pos, ERR_BUF_DEFAULTS)
  193. self.scope_node.buffer_defaults_node = decl.default
  194. self.scope_node.buffer_defaults_pos = decl.pos
  195. def visit_CVarDefNode(self, node):
  196. # This assumes only plain names and pointers are assignable on
  197. # declaration. Also, it makes use of the fact that a cdef decl
  198. # must appear before the first use, so we don't have to deal with
  199. # "i = 3; cdef int i = i" and can simply move the nodes around.
  200. try:
  201. self.visitchildren(node)
  202. stats = [node]
  203. newdecls = []
  204. for decl in node.declarators:
  205. declbase = decl
  206. while isinstance(declbase, Nodes.CPtrDeclaratorNode):
  207. declbase = declbase.base
  208. if isinstance(declbase, Nodes.CNameDeclaratorNode):
  209. if declbase.default is not None:
  210. if self.scope_type in ('cclass', 'pyclass', 'struct'):
  211. if isinstance(self.scope_node, Nodes.CClassDefNode):
  212. handler = self.specialattribute_handlers.get(decl.name)
  213. if handler:
  214. if decl is not declbase:
  215. raise PostParseError(decl.pos, ERR_INVALID_SPECIALATTR_TYPE)
  216. handler(decl)
  217. continue # Remove declaration
  218. raise PostParseError(decl.pos, ERR_CDEF_INCLASS)
  219. first_assignment = self.scope_type != 'module'
  220. stats.append(Nodes.SingleAssignmentNode(node.pos,
  221. lhs=ExprNodes.NameNode(node.pos, name=declbase.name),
  222. rhs=declbase.default, first=first_assignment))
  223. declbase.default = None
  224. newdecls.append(decl)
  225. node.declarators = newdecls
  226. return stats
  227. except PostParseError as e:
  228. # An error in a cdef clause is ok, simply remove the declaration
  229. # and try to move on to report more errors
  230. self.context.nonfatal_error(e)
  231. return None
  232. # Split parallel assignments (a,b = b,a) into separate partial
  233. # assignments that are executed rhs-first using temps. This
  234. # restructuring must be applied before type analysis so that known
  235. # types on rhs and lhs can be matched directly. It is required in
  236. # the case that the types cannot be coerced to a Python type in
  237. # order to assign from a tuple.
  238. def visit_SingleAssignmentNode(self, node):
  239. self.visitchildren(node)
  240. return self._visit_assignment_node(node, [node.lhs, node.rhs])
  241. def visit_CascadedAssignmentNode(self, node):
  242. self.visitchildren(node)
  243. return self._visit_assignment_node(node, node.lhs_list + [node.rhs])
  244. def _visit_assignment_node(self, node, expr_list):
  245. """Flatten parallel assignments into separate single
  246. assignments or cascaded assignments.
  247. """
  248. if sum([ 1 for expr in expr_list
  249. if expr.is_sequence_constructor or expr.is_string_literal ]) < 2:
  250. # no parallel assignments => nothing to do
  251. return node
  252. expr_list_list = []
  253. flatten_parallel_assignments(expr_list, expr_list_list)
  254. temp_refs = []
  255. eliminate_rhs_duplicates(expr_list_list, temp_refs)
  256. nodes = []
  257. for expr_list in expr_list_list:
  258. lhs_list = expr_list[:-1]
  259. rhs = expr_list[-1]
  260. if len(lhs_list) == 1:
  261. node = Nodes.SingleAssignmentNode(rhs.pos,
  262. lhs = lhs_list[0], rhs = rhs)
  263. else:
  264. node = Nodes.CascadedAssignmentNode(rhs.pos,
  265. lhs_list = lhs_list, rhs = rhs)
  266. nodes.append(node)
  267. if len(nodes) == 1:
  268. assign_node = nodes[0]
  269. else:
  270. assign_node = Nodes.ParallelAssignmentNode(nodes[0].pos, stats = nodes)
  271. if temp_refs:
  272. duplicates_and_temps = [ (temp.expression, temp)
  273. for temp in temp_refs ]
  274. sort_common_subsequences(duplicates_and_temps)
  275. for _, temp_ref in duplicates_and_temps[::-1]:
  276. assign_node = LetNode(temp_ref, assign_node)
  277. return assign_node
  278. def _flatten_sequence(self, seq, result):
  279. for arg in seq.args:
  280. if arg.is_sequence_constructor:
  281. self._flatten_sequence(arg, result)
  282. else:
  283. result.append(arg)
  284. return result
  285. def visit_DelStatNode(self, node):
  286. self.visitchildren(node)
  287. node.args = self._flatten_sequence(node, [])
  288. return node
  289. def visit_ExceptClauseNode(self, node):
  290. if node.is_except_as:
  291. # except-as must delete NameNode target at the end
  292. del_target = Nodes.DelStatNode(
  293. node.pos,
  294. args=[ExprNodes.NameNode(
  295. node.target.pos, name=node.target.name)],
  296. ignore_nonexisting=True)
  297. node.body = Nodes.StatListNode(
  298. node.pos,
  299. stats=[Nodes.TryFinallyStatNode(
  300. node.pos,
  301. body=node.body,
  302. finally_clause=Nodes.StatListNode(
  303. node.pos,
  304. stats=[del_target]))])
  305. self.visitchildren(node)
  306. return node
  307. def eliminate_rhs_duplicates(expr_list_list, ref_node_sequence):
  308. """Replace rhs items by LetRefNodes if they appear more than once.
  309. Creates a sequence of LetRefNodes that set up the required temps
  310. and appends them to ref_node_sequence. The input list is modified
  311. in-place.
  312. """
  313. seen_nodes = set()
  314. ref_nodes = {}
  315. def find_duplicates(node):
  316. if node.is_literal or node.is_name:
  317. # no need to replace those; can't include attributes here
  318. # as their access is not necessarily side-effect free
  319. return
  320. if node in seen_nodes:
  321. if node not in ref_nodes:
  322. ref_node = LetRefNode(node)
  323. ref_nodes[node] = ref_node
  324. ref_node_sequence.append(ref_node)
  325. else:
  326. seen_nodes.add(node)
  327. if node.is_sequence_constructor:
  328. for item in node.args:
  329. find_duplicates(item)
  330. for expr_list in expr_list_list:
  331. rhs = expr_list[-1]
  332. find_duplicates(rhs)
  333. if not ref_nodes:
  334. return
  335. def substitute_nodes(node):
  336. if node in ref_nodes:
  337. return ref_nodes[node]
  338. elif node.is_sequence_constructor:
  339. node.args = list(map(substitute_nodes, node.args))
  340. return node
  341. # replace nodes inside of the common subexpressions
  342. for node in ref_nodes:
  343. if node.is_sequence_constructor:
  344. node.args = list(map(substitute_nodes, node.args))
  345. # replace common subexpressions on all rhs items
  346. for expr_list in expr_list_list:
  347. expr_list[-1] = substitute_nodes(expr_list[-1])
  348. def sort_common_subsequences(items):
  349. """Sort items/subsequences so that all items and subsequences that
  350. an item contains appear before the item itself. This is needed
  351. because each rhs item must only be evaluated once, so its value
  352. must be evaluated first and then reused when packing sequences
  353. that contain it.
  354. This implies a partial order, and the sort must be stable to
  355. preserve the original order as much as possible, so we use a
  356. simple insertion sort (which is very fast for short sequences, the
  357. normal case in practice).
  358. """
  359. def contains(seq, x):
  360. for item in seq:
  361. if item is x:
  362. return True
  363. elif item.is_sequence_constructor and contains(item.args, x):
  364. return True
  365. return False
  366. def lower_than(a,b):
  367. return b.is_sequence_constructor and contains(b.args, a)
  368. for pos, item in enumerate(items):
  369. key = item[1] # the ResultRefNode which has already been injected into the sequences
  370. new_pos = pos
  371. for i in range(pos-1, -1, -1):
  372. if lower_than(key, items[i][0]):
  373. new_pos = i
  374. if new_pos != pos:
  375. for i in range(pos, new_pos, -1):
  376. items[i] = items[i-1]
  377. items[new_pos] = item
  378. def unpack_string_to_character_literals(literal):
  379. chars = []
  380. pos = literal.pos
  381. stype = literal.__class__
  382. sval = literal.value
  383. sval_type = sval.__class__
  384. for char in sval:
  385. cval = sval_type(char)
  386. chars.append(stype(pos, value=cval, constant_result=cval))
  387. return chars
  388. def flatten_parallel_assignments(input, output):
  389. # The input is a list of expression nodes, representing the LHSs
  390. # and RHS of one (possibly cascaded) assignment statement. For
  391. # sequence constructors, rearranges the matching parts of both
  392. # sides into a list of equivalent assignments between the
  393. # individual elements. This transformation is applied
  394. # recursively, so that nested structures get matched as well.
  395. rhs = input[-1]
  396. if (not (rhs.is_sequence_constructor or isinstance(rhs, ExprNodes.UnicodeNode))
  397. or not sum([lhs.is_sequence_constructor for lhs in input[:-1]])):
  398. output.append(input)
  399. return
  400. complete_assignments = []
  401. if rhs.is_sequence_constructor:
  402. rhs_args = rhs.args
  403. elif rhs.is_string_literal:
  404. rhs_args = unpack_string_to_character_literals(rhs)
  405. rhs_size = len(rhs_args)
  406. lhs_targets = [[] for _ in range(rhs_size)]
  407. starred_assignments = []
  408. for lhs in input[:-1]:
  409. if not lhs.is_sequence_constructor:
  410. if lhs.is_starred:
  411. error(lhs.pos, "starred assignment target must be in a list or tuple")
  412. complete_assignments.append(lhs)
  413. continue
  414. lhs_size = len(lhs.args)
  415. starred_targets = sum([1 for expr in lhs.args if expr.is_starred])
  416. if starred_targets > 1:
  417. error(lhs.pos, "more than 1 starred expression in assignment")
  418. output.append([lhs,rhs])
  419. continue
  420. elif lhs_size - starred_targets > rhs_size:
  421. error(lhs.pos, "need more than %d value%s to unpack"
  422. % (rhs_size, (rhs_size != 1) and 's' or ''))
  423. output.append([lhs,rhs])
  424. continue
  425. elif starred_targets:
  426. map_starred_assignment(lhs_targets, starred_assignments,
  427. lhs.args, rhs_args)
  428. elif lhs_size < rhs_size:
  429. error(lhs.pos, "too many values to unpack (expected %d, got %d)"
  430. % (lhs_size, rhs_size))
  431. output.append([lhs,rhs])
  432. continue
  433. else:
  434. for targets, expr in zip(lhs_targets, lhs.args):
  435. targets.append(expr)
  436. if complete_assignments:
  437. complete_assignments.append(rhs)
  438. output.append(complete_assignments)
  439. # recursively flatten partial assignments
  440. for cascade, rhs in zip(lhs_targets, rhs_args):
  441. if cascade:
  442. cascade.append(rhs)
  443. flatten_parallel_assignments(cascade, output)
  444. # recursively flatten starred assignments
  445. for cascade in starred_assignments:
  446. if cascade[0].is_sequence_constructor:
  447. flatten_parallel_assignments(cascade, output)
  448. else:
  449. output.append(cascade)
  450. def map_starred_assignment(lhs_targets, starred_assignments, lhs_args, rhs_args):
  451. # Appends the fixed-position LHS targets to the target list that
  452. # appear left and right of the starred argument.
  453. #
  454. # The starred_assignments list receives a new tuple
  455. # (lhs_target, rhs_values_list) that maps the remaining arguments
  456. # (those that match the starred target) to a list.
  457. # left side of the starred target
  458. for i, (targets, expr) in enumerate(zip(lhs_targets, lhs_args)):
  459. if expr.is_starred:
  460. starred = i
  461. lhs_remaining = len(lhs_args) - i - 1
  462. break
  463. targets.append(expr)
  464. else:
  465. raise InternalError("no starred arg found when splitting starred assignment")
  466. # right side of the starred target
  467. for i, (targets, expr) in enumerate(zip(lhs_targets[-lhs_remaining:],
  468. lhs_args[starred + 1:])):
  469. targets.append(expr)
  470. # the starred target itself, must be assigned a (potentially empty) list
  471. target = lhs_args[starred].target # unpack starred node
  472. starred_rhs = rhs_args[starred:]
  473. if lhs_remaining:
  474. starred_rhs = starred_rhs[:-lhs_remaining]
  475. if starred_rhs:
  476. pos = starred_rhs[0].pos
  477. else:
  478. pos = target.pos
  479. starred_assignments.append([
  480. target, ExprNodes.ListNode(pos=pos, args=starred_rhs)])
  481. class PxdPostParse(CythonTransform, SkipDeclarations):
  482. """
  483. Basic interpretation/validity checking that should only be
  484. done on pxd trees.
  485. A lot of this checking currently happens in the parser; but
  486. what is listed below happens here.
  487. - "def" functions are let through only if they fill the
  488. getbuffer/releasebuffer slots
  489. - cdef functions are let through only if they are on the
  490. top level and are declared "inline"
  491. """
  492. ERR_INLINE_ONLY = "function definition in pxd file must be declared 'cdef inline'"
  493. ERR_NOGO_WITH_INLINE = "inline function definition in pxd file cannot be '%s'"
  494. def __call__(self, node):
  495. self.scope_type = 'pxd'
  496. return super(PxdPostParse, self).__call__(node)
  497. def visit_CClassDefNode(self, node):
  498. old = self.scope_type
  499. self.scope_type = 'cclass'
  500. self.visitchildren(node)
  501. self.scope_type = old
  502. return node
  503. def visit_FuncDefNode(self, node):
  504. # FuncDefNode always come with an implementation (without
  505. # an imp they are CVarDefNodes..)
  506. err = self.ERR_INLINE_ONLY
  507. if (isinstance(node, Nodes.DefNode) and self.scope_type == 'cclass'
  508. and node.name in ('__getbuffer__', '__releasebuffer__')):
  509. err = None # allow these slots
  510. if isinstance(node, Nodes.CFuncDefNode):
  511. if (u'inline' in node.modifiers and
  512. self.scope_type in ('pxd', 'cclass')):
  513. node.inline_in_pxd = True
  514. if node.visibility != 'private':
  515. err = self.ERR_NOGO_WITH_INLINE % node.visibility
  516. elif node.api:
  517. err = self.ERR_NOGO_WITH_INLINE % 'api'
  518. else:
  519. err = None # allow inline function
  520. else:
  521. err = self.ERR_INLINE_ONLY
  522. if err:
  523. self.context.nonfatal_error(PostParseError(node.pos, err))
  524. return None
  525. else:
  526. return node
  527. class TrackNumpyAttributes(VisitorTransform, SkipDeclarations):
  528. # TODO: Make name handling as good as in InterpretCompilerDirectives() below - probably best to merge the two.
  529. def __init__(self):
  530. super(TrackNumpyAttributes, self).__init__()
  531. self.numpy_module_names = set()
  532. def visit_CImportStatNode(self, node):
  533. if node.module_name == u"numpy":
  534. self.numpy_module_names.add(node.as_name or u"numpy")
  535. return node
  536. def visit_AttributeNode(self, node):
  537. self.visitchildren(node)
  538. if node.obj.is_name and node.obj.name in self.numpy_module_names:
  539. node.is_numpy_attribute = True
  540. return node
  541. visit_Node = VisitorTransform.recurse_to_children
  542. class InterpretCompilerDirectives(CythonTransform):
  543. """
  544. After parsing, directives can be stored in a number of places:
  545. - #cython-comments at the top of the file (stored in ModuleNode)
  546. - Command-line arguments overriding these
  547. - @cython.directivename decorators
  548. - with cython.directivename: statements
  549. This transform is responsible for interpreting these various sources
  550. and store the directive in two ways:
  551. - Set the directives attribute of the ModuleNode for global directives.
  552. - Use a CompilerDirectivesNode to override directives for a subtree.
  553. (The first one is primarily to not have to modify with the tree
  554. structure, so that ModuleNode stay on top.)
  555. The directives are stored in dictionaries from name to value in effect.
  556. Each such dictionary is always filled in for all possible directives,
  557. using default values where no value is given by the user.
  558. The available directives are controlled in Options.py.
  559. Note that we have to run this prior to analysis, and so some minor
  560. duplication of functionality has to occur: We manually track cimports
  561. and which names the "cython" module may have been imported to.
  562. """
  563. unop_method_nodes = {
  564. 'typeof': ExprNodes.TypeofNode,
  565. 'operator.address': ExprNodes.AmpersandNode,
  566. 'operator.dereference': ExprNodes.DereferenceNode,
  567. 'operator.preincrement' : ExprNodes.inc_dec_constructor(True, '++'),
  568. 'operator.predecrement' : ExprNodes.inc_dec_constructor(True, '--'),
  569. 'operator.postincrement': ExprNodes.inc_dec_constructor(False, '++'),
  570. 'operator.postdecrement': ExprNodes.inc_dec_constructor(False, '--'),
  571. 'operator.typeid' : ExprNodes.TypeidNode,
  572. # For backwards compatibility.
  573. 'address': ExprNodes.AmpersandNode,
  574. }
  575. binop_method_nodes = {
  576. 'operator.comma' : ExprNodes.c_binop_constructor(','),
  577. }
  578. special_methods = set(['declare', 'union', 'struct', 'typedef',
  579. 'sizeof', 'cast', 'pointer', 'compiled',
  580. 'NULL', 'fused_type', 'parallel'])
  581. special_methods.update(unop_method_nodes)
  582. valid_parallel_directives = set([
  583. "parallel",
  584. "prange",
  585. "threadid",
  586. #"threadsavailable",
  587. ])
  588. def __init__(self, context, compilation_directive_defaults):
  589. super(InterpretCompilerDirectives, self).__init__(context)
  590. self.cython_module_names = set()
  591. self.directive_names = {'staticmethod': 'staticmethod'}
  592. self.parallel_directives = {}
  593. directives = copy.deepcopy(Options.get_directive_defaults())
  594. for key, value in compilation_directive_defaults.items():
  595. directives[_unicode(key)] = copy.deepcopy(value)
  596. self.directives = directives
  597. def check_directive_scope(self, pos, directive, scope):
  598. legal_scopes = Options.directive_scopes.get(directive, None)
  599. if legal_scopes and scope not in legal_scopes:
  600. self.context.nonfatal_error(PostParseError(pos, 'The %s compiler directive '
  601. 'is not allowed in %s scope' % (directive, scope)))
  602. return False
  603. else:
  604. if directive not in Options.directive_types:
  605. error(pos, "Invalid directive: '%s'." % (directive,))
  606. return True
  607. # Set up processing and handle the cython: comments.
  608. def visit_ModuleNode(self, node):
  609. for key in sorted(node.directive_comments):
  610. if not self.check_directive_scope(node.pos, key, 'module'):
  611. self.wrong_scope_error(node.pos, key, 'module')
  612. del node.directive_comments[key]
  613. self.module_scope = node.scope
  614. self.directives.update(node.directive_comments)
  615. node.directives = self.directives
  616. node.parallel_directives = self.parallel_directives
  617. self.visitchildren(node)
  618. node.cython_module_names = self.cython_module_names
  619. return node
  620. # The following four functions track imports and cimports that
  621. # begin with "cython"
  622. def is_cython_directive(self, name):
  623. return (name in Options.directive_types or
  624. name in self.special_methods or
  625. PyrexTypes.parse_basic_type(name))
  626. def is_parallel_directive(self, full_name, pos):
  627. """
  628. Checks to see if fullname (e.g. cython.parallel.prange) is a valid
  629. parallel directive. If it is a star import it also updates the
  630. parallel_directives.
  631. """
  632. result = (full_name + ".").startswith("cython.parallel.")
  633. if result:
  634. directive = full_name.split('.')
  635. if full_name == u"cython.parallel":
  636. self.parallel_directives[u"parallel"] = u"cython.parallel"
  637. elif full_name == u"cython.parallel.*":
  638. for name in self.valid_parallel_directives:
  639. self.parallel_directives[name] = u"cython.parallel.%s" % name
  640. elif (len(directive) != 3 or
  641. directive[-1] not in self.valid_parallel_directives):
  642. error(pos, "No such directive: %s" % full_name)
  643. self.module_scope.use_utility_code(
  644. UtilityCode.load_cached("InitThreads", "ModuleSetupCode.c"))
  645. return result
  646. def visit_CImportStatNode(self, node):
  647. if node.module_name == u"cython":
  648. self.cython_module_names.add(node.as_name or u"cython")
  649. elif node.module_name.startswith(u"cython."):
  650. if node.module_name.startswith(u"cython.parallel."):
  651. error(node.pos, node.module_name + " is not a module")
  652. if node.module_name == u"cython.parallel":
  653. if node.as_name and node.as_name != u"cython":
  654. self.parallel_directives[node.as_name] = node.module_name
  655. else:
  656. self.cython_module_names.add(u"cython")
  657. self.parallel_directives[
  658. u"cython.parallel"] = node.module_name
  659. self.module_scope.use_utility_code(
  660. UtilityCode.load_cached("InitThreads", "ModuleSetupCode.c"))
  661. elif node.as_name:
  662. self.directive_names[node.as_name] = node.module_name[7:]
  663. else:
  664. self.cython_module_names.add(u"cython")
  665. # if this cimport was a compiler directive, we don't
  666. # want to leave the cimport node sitting in the tree
  667. return None
  668. return node
  669. def visit_FromCImportStatNode(self, node):
  670. if not node.relative_level and (
  671. node.module_name == u"cython" or node.module_name.startswith(u"cython.")):
  672. submodule = (node.module_name + u".")[7:]
  673. newimp = []
  674. for pos, name, as_name, kind in node.imported_names:
  675. full_name = submodule + name
  676. qualified_name = u"cython." + full_name
  677. if self.is_parallel_directive(qualified_name, node.pos):
  678. # from cython cimport parallel, or
  679. # from cython.parallel cimport parallel, prange, ...
  680. self.parallel_directives[as_name or name] = qualified_name
  681. elif self.is_cython_directive(full_name):
  682. self.directive_names[as_name or name] = full_name
  683. if kind is not None:
  684. self.context.nonfatal_error(PostParseError(pos,
  685. "Compiler directive imports must be plain imports"))
  686. else:
  687. newimp.append((pos, name, as_name, kind))
  688. if not newimp:
  689. return None
  690. node.imported_names = newimp
  691. return node
  692. def visit_FromImportStatNode(self, node):
  693. if (node.module.module_name.value == u"cython") or \
  694. node.module.module_name.value.startswith(u"cython."):
  695. submodule = (node.module.module_name.value + u".")[7:]
  696. newimp = []
  697. for name, name_node in node.items:
  698. full_name = submodule + name
  699. qualified_name = u"cython." + full_name
  700. if self.is_parallel_directive(qualified_name, node.pos):
  701. self.parallel_directives[name_node.name] = qualified_name
  702. elif self.is_cython_directive(full_name):
  703. self.directive_names[name_node.name] = full_name
  704. else:
  705. newimp.append((name, name_node))
  706. if not newimp:
  707. return None
  708. node.items = newimp
  709. return node
  710. def visit_SingleAssignmentNode(self, node):
  711. if isinstance(node.rhs, ExprNodes.ImportNode):
  712. module_name = node.rhs.module_name.value
  713. is_parallel = (module_name + u".").startswith(u"cython.parallel.")
  714. if module_name != u"cython" and not is_parallel:
  715. return node
  716. module_name = node.rhs.module_name.value
  717. as_name = node.lhs.name
  718. node = Nodes.CImportStatNode(node.pos,
  719. module_name = module_name,
  720. as_name = as_name)
  721. node = self.visit_CImportStatNode(node)
  722. else:
  723. self.visitchildren(node)
  724. return node
  725. def visit_NameNode(self, node):
  726. if node.name in self.cython_module_names:
  727. node.is_cython_module = True
  728. else:
  729. directive = self.directive_names.get(node.name)
  730. if directive is not None:
  731. node.cython_attribute = directive
  732. return node
  733. def visit_NewExprNode(self, node):
  734. self.visit(node.cppclass)
  735. self.visitchildren(node)
  736. return node
  737. def try_to_parse_directives(self, node):
  738. # If node is the contents of an directive (in a with statement or
  739. # decorator), returns a list of (directivename, value) pairs.
  740. # Otherwise, returns None
  741. if isinstance(node, ExprNodes.CallNode):
  742. self.visit(node.function)
  743. optname = node.function.as_cython_attribute()
  744. if optname:
  745. directivetype = Options.directive_types.get(optname)
  746. if directivetype:
  747. args, kwds = node.explicit_args_kwds()
  748. directives = []
  749. key_value_pairs = []
  750. if kwds is not None and directivetype is not dict:
  751. for keyvalue in kwds.key_value_pairs:
  752. key, value = keyvalue
  753. sub_optname = "%s.%s" % (optname, key.value)
  754. if Options.directive_types.get(sub_optname):
  755. directives.append(self.try_to_parse_directive(sub_optname, [value], None, keyvalue.pos))
  756. else:
  757. key_value_pairs.append(keyvalue)
  758. if not key_value_pairs:
  759. kwds = None
  760. else:
  761. kwds.key_value_pairs = key_value_pairs
  762. if directives and not kwds and not args:
  763. return directives
  764. directives.append(self.try_to_parse_directive(optname, args, kwds, node.function.pos))
  765. return directives
  766. elif isinstance(node, (ExprNodes.AttributeNode, ExprNodes.NameNode)):
  767. self.visit(node)
  768. optname = node.as_cython_attribute()
  769. if optname:
  770. directivetype = Options.directive_types.get(optname)
  771. if directivetype is bool:
  772. arg = ExprNodes.BoolNode(node.pos, value=True)
  773. return [self.try_to_parse_directive(optname, [arg], None, node.pos)]
  774. elif directivetype is None:
  775. return [(optname, None)]
  776. else:
  777. raise PostParseError(
  778. node.pos, "The '%s' directive should be used as a function call." % optname)
  779. return None
  780. def try_to_parse_directive(self, optname, args, kwds, pos):
  781. if optname == 'np_pythran' and not self.context.cpp:
  782. raise PostParseError(pos, 'The %s directive can only be used in C++ mode.' % optname)
  783. elif optname == 'exceptval':
  784. # default: exceptval(None, check=True)
  785. arg_error = len(args) > 1
  786. check = True
  787. if kwds and kwds.key_value_pairs:
  788. kw = kwds.key_value_pairs[0]
  789. if (len(kwds.key_value_pairs) == 1 and
  790. kw.key.is_string_literal and kw.key.value == 'check' and
  791. isinstance(kw.value, ExprNodes.BoolNode)):
  792. check = kw.value.value
  793. else:
  794. arg_error = True
  795. if arg_error:
  796. raise PostParseError(
  797. pos, 'The exceptval directive takes 0 or 1 positional arguments and the boolean keyword "check"')
  798. return ('exceptval', (args[0] if args else None, check))
  799. directivetype = Options.directive_types.get(optname)
  800. if len(args) == 1 and isinstance(args[0], ExprNodes.NoneNode):
  801. return optname, Options.get_directive_defaults()[optname]
  802. elif directivetype is bool:
  803. if kwds is not None or len(args) != 1 or not isinstance(args[0], ExprNodes.BoolNode):
  804. raise PostParseError(pos,
  805. 'The %s directive takes one compile-time boolean argument' % optname)
  806. return (optname, args[0].value)
  807. elif directivetype is int:
  808. if kwds is not None or len(args) != 1 or not isinstance(args[0], ExprNodes.IntNode):
  809. raise PostParseError(pos,
  810. 'The %s directive takes one compile-time integer argument' % optname)
  811. return (optname, int(args[0].value))
  812. elif directivetype is str:
  813. if kwds is not None or len(args) != 1 or not isinstance(
  814. args[0], (ExprNodes.StringNode, ExprNodes.UnicodeNode)):
  815. raise PostParseError(pos,
  816. 'The %s directive takes one compile-time string argument' % optname)
  817. return (optname, str(args[0].value))
  818. elif directivetype is type:
  819. if kwds is not None or len(args) != 1:
  820. raise PostParseError(pos,
  821. 'The %s directive takes one type argument' % optname)
  822. return (optname, args[0])
  823. elif directivetype is dict:
  824. if len(args) != 0:
  825. raise PostParseError(pos,
  826. 'The %s directive takes no prepositional arguments' % optname)
  827. return optname, dict([(key.value, value) for key, value in kwds.key_value_pairs])
  828. elif directivetype is list:
  829. if kwds and len(kwds.key_value_pairs) != 0:
  830. raise PostParseError(pos,
  831. 'The %s directive takes no keyword arguments' % optname)
  832. return optname, [ str(arg.value) for arg in args ]
  833. elif callable(directivetype):
  834. if kwds is not None or len(args) != 1 or not isinstance(
  835. args[0], (ExprNodes.StringNode, ExprNodes.UnicodeNode)):
  836. raise PostParseError(pos,
  837. 'The %s directive takes one compile-time string argument' % optname)
  838. return (optname, directivetype(optname, str(args[0].value)))
  839. else:
  840. assert False
  841. def visit_with_directives(self, body, directives):
  842. olddirectives = self.directives
  843. newdirectives = copy.copy(olddirectives)
  844. newdirectives.update(directives)
  845. self.directives = newdirectives
  846. assert isinstance(body, Nodes.StatListNode), body
  847. retbody = self.visit_Node(body)
  848. directive = Nodes.CompilerDirectivesNode(pos=retbody.pos, body=retbody,
  849. directives=newdirectives)
  850. self.directives = olddirectives
  851. return directive
  852. # Handle decorators
  853. def visit_FuncDefNode(self, node):
  854. directives = self._extract_directives(node, 'function')
  855. if not directives:
  856. return self.visit_Node(node)
  857. body = Nodes.StatListNode(node.pos, stats=[node])
  858. return self.visit_with_directives(body, directives)
  859. def visit_CVarDefNode(self, node):
  860. directives = self._extract_directives(node, 'function')
  861. if not directives:
  862. return self.visit_Node(node)
  863. for name, value in directives.items():
  864. if name == 'locals':
  865. node.directive_locals = value
  866. elif name not in ('final', 'staticmethod'):
  867. self.context.nonfatal_error(PostParseError(
  868. node.pos,
  869. "Cdef functions can only take cython.locals(), "
  870. "staticmethod, or final decorators, got %s." % name))
  871. body = Nodes.StatListNode(node.pos, stats=[node])
  872. return self.visit_with_directives(body, directives)
  873. def visit_CClassDefNode(self, node):
  874. directives = self._extract_directives(node, 'cclass')
  875. if not directives:
  876. return self.visit_Node(node)
  877. body = Nodes.StatListNode(node.pos, stats=[node])
  878. return self.visit_with_directives(body, directives)
  879. def visit_CppClassNode(self, node):
  880. directives = self._extract_directives(node, 'cppclass')
  881. if not directives:
  882. return self.visit_Node(node)
  883. body = Nodes.StatListNode(node.pos, stats=[node])
  884. return self.visit_with_directives(body, directives)
  885. def visit_PyClassDefNode(self, node):
  886. directives = self._extract_directives(node, 'class')
  887. if not directives:
  888. return self.visit_Node(node)
  889. body = Nodes.StatListNode(node.pos, stats=[node])
  890. return self.visit_with_directives(body, directives)
  891. def _extract_directives(self, node, scope_name):
  892. if not node.decorators:
  893. return {}
  894. # Split the decorators into two lists -- real decorators and directives
  895. directives = []
  896. realdecs = []
  897. both = []
  898. # Decorators coming first take precedence.
  899. for dec in node.decorators[::-1]:
  900. new_directives = self.try_to_parse_directives(dec.decorator)
  901. if new_directives is not None:
  902. for directive in new_directives:
  903. if self.check_directive_scope(node.pos, directive[0], scope_name):
  904. name, value = directive
  905. if self.directives.get(name, object()) != value:
  906. directives.append(directive)
  907. if directive[0] == 'staticmethod':
  908. both.append(dec)
  909. # Adapt scope type based on decorators that change it.
  910. if directive[0] == 'cclass' and scope_name == 'class':
  911. scope_name = 'cclass'
  912. else:
  913. realdecs.append(dec)
  914. if realdecs and (scope_name == 'cclass' or
  915. isinstance(node, (Nodes.CFuncDefNode, Nodes.CClassDefNode, Nodes.CVarDefNode))):
  916. raise PostParseError(realdecs[0].pos, "Cdef functions/classes cannot take arbitrary decorators.")
  917. node.decorators = realdecs[::-1] + both[::-1]
  918. # merge or override repeated directives
  919. optdict = {}
  920. for directive in directives:
  921. name, value = directive
  922. if name in optdict:
  923. old_value = optdict[name]
  924. # keywords and arg lists can be merged, everything
  925. # else overrides completely
  926. if isinstance(old_value, dict):
  927. old_value.update(value)
  928. elif isinstance(old_value, list):
  929. old_value.extend(value)
  930. else:
  931. optdict[name] = value
  932. else:
  933. optdict[name] = value
  934. return optdict
  935. # Handle with statements
  936. def visit_WithStatNode(self, node):
  937. directive_dict = {}
  938. for directive in self.try_to_parse_directives(node.manager) or []:
  939. if directive is not None:
  940. if node.target is not None:
  941. self.context.nonfatal_error(
  942. PostParseError(node.pos, "Compiler directive with statements cannot contain 'as'"))
  943. else:
  944. name, value = directive
  945. if name in ('nogil', 'gil'):
  946. # special case: in pure mode, "with nogil" spells "with cython.nogil"
  947. node = Nodes.GILStatNode(node.pos, state = name, body = node.body)
  948. return self.visit_Node(node)
  949. if self.check_directive_scope(node.pos, name, 'with statement'):
  950. directive_dict[name] = value
  951. if directive_dict:
  952. return self.visit_with_directives(node.body, directive_dict)
  953. return self.visit_Node(node)
  954. class ParallelRangeTransform(CythonTransform, SkipDeclarations):
  955. """
  956. Transform cython.parallel stuff. The parallel_directives come from the
  957. module node, set there by InterpretCompilerDirectives.
  958. x = cython.parallel.threadavailable() -> ParallelThreadAvailableNode
  959. with nogil, cython.parallel.parallel(): -> ParallelWithBlockNode
  960. print cython.parallel.threadid() -> ParallelThreadIdNode
  961. for i in cython.parallel.prange(...): -> ParallelRangeNode
  962. ...
  963. """
  964. # a list of names, maps 'cython.parallel.prange' in the code to
  965. # ['cython', 'parallel', 'prange']
  966. parallel_directive = None
  967. # Indicates whether a namenode in an expression is the cython module
  968. namenode_is_cython_module = False
  969. # Keep track of whether we are the context manager of a 'with' statement
  970. in_context_manager_section = False
  971. # One of 'prange' or 'with parallel'. This is used to disallow closely
  972. # nested 'with parallel:' blocks
  973. state = None
  974. directive_to_node = {
  975. u"cython.parallel.parallel": Nodes.ParallelWithBlockNode,
  976. # u"cython.parallel.threadsavailable": ExprNodes.ParallelThreadsAvailableNode,
  977. u"cython.parallel.threadid": ExprNodes.ParallelThreadIdNode,
  978. u"cython.parallel.prange": Nodes.ParallelRangeNode,
  979. }
  980. def node_is_parallel_directive(self, node):
  981. return node.name in self.parallel_directives or node.is_cython_module
  982. def get_directive_class_node(self, node):
  983. """
  984. Figure out which parallel directive was used and return the associated
  985. Node class.
  986. E.g. for a cython.parallel.prange() call we return ParallelRangeNode
  987. """
  988. if self.namenode_is_cython_module:
  989. directive = '.'.join(self.parallel_directive)
  990. else:
  991. directive = self.parallel_directives[self.parallel_directive[0]]
  992. directive = '%s.%s' % (directive,
  993. '.'.join(self.parallel_directive[1:]))
  994. directive = directive.rstrip('.')
  995. cls = self.directive_to_node.get(directive)
  996. if cls is None and not (self.namenode_is_cython_module and
  997. self.parallel_directive[0] != 'parallel'):
  998. error(node.pos, "Invalid directive: %s" % directive)
  999. self.namenode_is_cython_module = False
  1000. self.parallel_directive = None
  1001. return cls
  1002. def visit_ModuleNode(self, node):
  1003. """
  1004. If any parallel directives were imported, copy them over and visit
  1005. the AST
  1006. """
  1007. if node.parallel_directives:
  1008. self.parallel_directives = node.parallel_directives
  1009. return self.visit_Node(node)
  1010. # No parallel directives were imported, so they can't be used :)
  1011. return node
  1012. def visit_NameNode(self, node):
  1013. if self.node_is_parallel_directive(node):
  1014. self.parallel_directive = [node.name]
  1015. self.namenode_is_cython_module = node.is_cython_module
  1016. return node
  1017. def visit_AttributeNode(self, node):
  1018. self.visitchildren(node)
  1019. if self.parallel_directive:
  1020. self.parallel_directive.append(node.attribute)
  1021. return node
  1022. def visit_CallNode(self, node):
  1023. self.visit(node.function)
  1024. if not self.parallel_directive:
  1025. return node
  1026. # We are a parallel directive, replace this node with the
  1027. # corresponding ParallelSomethingSomething node
  1028. if isinstance(node, ExprNodes.GeneralCallNode):
  1029. args = node.positional_args.args
  1030. kwargs = node.keyword_args
  1031. else:
  1032. args = node.args
  1033. kwargs = {}
  1034. parallel_directive_class = self.get_directive_class_node(node)
  1035. if parallel_directive_class:
  1036. # Note: in case of a parallel() the body is set by
  1037. # visit_WithStatNode
  1038. node = parallel_directive_class(node.pos, args=args, kwargs=kwargs)
  1039. return node
  1040. def visit_WithStatNode(self, node):
  1041. "Rewrite with cython.parallel.parallel() blocks"
  1042. newnode = self.visit(node.manager)
  1043. if isinstance(newnode, Nodes.ParallelWithBlockNode):
  1044. if self.state == 'parallel with':
  1045. error(node.manager.pos,
  1046. "Nested parallel with blocks are disallowed")
  1047. self.state = 'parallel with'
  1048. body = self.visit(node.body)
  1049. self.state = None
  1050. newnode.body = body
  1051. return newnode
  1052. elif self.parallel_directive:
  1053. parallel_directive_class = self.get_directive_class_node(node)
  1054. if not parallel_directive_class:
  1055. # There was an error, stop here and now
  1056. return None
  1057. if parallel_directive_class is Nodes.ParallelWithBlockNode:
  1058. error(node.pos, "The parallel directive must be called")
  1059. return None
  1060. node.body = self.visit(node.body)
  1061. return node
  1062. def visit_ForInStatNode(self, node):
  1063. "Rewrite 'for i in cython.parallel.prange(...):'"
  1064. self.visit(node.iterator)
  1065. self.visit(node.target)
  1066. in_prange = isinstance(node.iterator.sequence,
  1067. Nodes.ParallelRangeNode)
  1068. previous_state = self.state
  1069. if in_prange:
  1070. # This will replace the entire ForInStatNode, so copy the
  1071. # attributes
  1072. parallel_range_node = node.iterator.sequence
  1073. parallel_range_node.target = node.target
  1074. parallel_range_node.body = node.body
  1075. parallel_range_node.else_clause = node.else_clause
  1076. node = parallel_range_node
  1077. if not isinstance(node.target, ExprNodes.NameNode):
  1078. error(node.target.pos,
  1079. "Can only iterate over an iteration variable")
  1080. self.state = 'prange'
  1081. self.visit(node.body)
  1082. self.state = previous_state
  1083. self.visit(node.else_clause)
  1084. return node
  1085. def visit(self, node):
  1086. "Visit a node that may be None"
  1087. if node is not None:
  1088. return super(ParallelRangeTransform, self).visit(node)
  1089. class WithTransform(CythonTransform, SkipDeclarations):
  1090. def visit_WithStatNode(self, node):
  1091. self.visitchildren(node, 'body')
  1092. pos = node.pos
  1093. is_async = node.is_async
  1094. body, target, manager = node.body, node.target, node.manager
  1095. node.enter_call = ExprNodes.SimpleCallNode(
  1096. pos, function=ExprNodes.AttributeNode(
  1097. pos, obj=ExprNodes.CloneNode(manager),
  1098. attribute=EncodedString('__aenter__' if is_async else '__enter__'),
  1099. is_special_lookup=True),
  1100. args=[],
  1101. is_temp=True)
  1102. if is_async:
  1103. node.enter_call = ExprNodes.AwaitExprNode(pos, arg=node.enter_call)
  1104. if target is not None:
  1105. body = Nodes.StatListNode(
  1106. pos, stats=[
  1107. Nodes.WithTargetAssignmentStatNode(
  1108. pos, lhs=target, with_node=node),
  1109. body])
  1110. excinfo_target = ExprNodes.TupleNode(pos, slow=True, args=[
  1111. ExprNodes.ExcValueNode(pos) for _ in range(3)])
  1112. except_clause = Nodes.ExceptClauseNode(
  1113. pos, body=Nodes.IfStatNode(
  1114. pos, if_clauses=[
  1115. Nodes.IfClauseNode(
  1116. pos, condition=ExprNodes.NotNode(
  1117. pos, operand=ExprNodes.WithExitCallNode(
  1118. pos, with_stat=node,
  1119. test_if_run=False,
  1120. args=excinfo_target,
  1121. await_expr=ExprNodes.AwaitExprNode(pos, arg=None) if is_async else None)),
  1122. body=Nodes.ReraiseStatNode(pos),
  1123. ),
  1124. ],
  1125. else_clause=None),
  1126. pattern=None,
  1127. target=None,
  1128. excinfo_target=excinfo_target,
  1129. )
  1130. node.body = Nodes.TryFinallyStatNode(
  1131. pos, body=Nodes.TryExceptStatNode(
  1132. pos, body=body,
  1133. except_clauses=[except_clause],
  1134. else_clause=None,
  1135. ),
  1136. finally_clause=Nodes.ExprStatNode(
  1137. pos, expr=ExprNodes.WithExitCallNode(
  1138. pos, with_stat=node,
  1139. test_if_run=True,
  1140. args=ExprNodes.TupleNode(
  1141. pos, args=[ExprNodes.NoneNode(pos) for _ in range(3)]),
  1142. await_expr=ExprNodes.AwaitExprNode(pos, arg=None) if is_async else None)),
  1143. handle_error_case=False,
  1144. )
  1145. return node
  1146. def visit_ExprNode(self, node):
  1147. # With statements are never inside expressions.
  1148. return node
  1149. class DecoratorTransform(ScopeTrackingTransform, SkipDeclarations):
  1150. """
  1151. Transforms method decorators in cdef classes into nested calls or properties.
  1152. Python-style decorator properties are transformed into a PropertyNode
  1153. with up to the three getter, setter and deleter DefNodes.
  1154. The functional style isn't supported yet.
  1155. """
  1156. _properties = None
  1157. _map_property_attribute = {
  1158. 'getter': '__get__',
  1159. 'setter': '__set__',
  1160. 'deleter': '__del__',
  1161. }.get
  1162. def visit_CClassDefNode(self, node):
  1163. if self._properties is None:
  1164. self._properties = []
  1165. self._properties.append({})
  1166. super(DecoratorTransform, self).visit_CClassDefNode(node)
  1167. self._properties.pop()
  1168. return node
  1169. def visit_PropertyNode(self, node):
  1170. # Low-level warning for other code until we can convert all our uses over.
  1171. level = 2 if isinstance(node.pos[0], str) else 0
  1172. warning(node.pos, "'property %s:' syntax is deprecated, use '@property'" % node.name, level)
  1173. return node
  1174. def visit_DefNode(self, node):
  1175. scope_type = self.scope_type
  1176. node = self.visit_FuncDefNode(node)
  1177. if scope_type != 'cclass' or not node.decorators:
  1178. return node
  1179. # transform @property decorators
  1180. properties = self._properties[-1]
  1181. for decorator_node in node.decorators[::-1]:
  1182. decorator = decorator_node.decorator
  1183. if decorator.is_name and decorator.name == 'property':
  1184. if len(node.decorators) > 1:
  1185. return self._reject_decorated_property(node, decorator_node)
  1186. name = node.name
  1187. node.name = EncodedString('__get__')
  1188. node.decorators.remove(decorator_node)
  1189. stat_list = [node]
  1190. if name in properties:
  1191. prop = properties[name]
  1192. prop.pos = node.pos
  1193. prop.doc = node.doc
  1194. prop.body.stats = stat_list
  1195. return []
  1196. prop = Nodes.PropertyNode(node.pos, name=name)
  1197. prop.doc = node.doc
  1198. prop.body = Nodes.StatListNode(node.pos, stats=stat_list)
  1199. properties[name] = prop
  1200. return [prop]
  1201. elif decorator.is_attribute and decorator.obj.name in properties:
  1202. handler_name = self._map_property_attribute(decorator.attribute)
  1203. if handler_name:
  1204. if decorator.obj.name != node.name:
  1205. # CPython does not generate an error or warning, but not something useful either.
  1206. error(decorator_node.pos,
  1207. "Mismatching property names, expected '%s', got '%s'" % (
  1208. decorator.obj.name, node.name))
  1209. elif len(node.decorators) > 1:
  1210. return self._reject_decorated_property(node, decorator_node)
  1211. else:
  1212. return self._add_to_property(properties, node, handler_name, decorator_node)
  1213. # we clear node.decorators, so we need to set the
  1214. # is_staticmethod/is_classmethod attributes now
  1215. for decorator in node.decorators:
  1216. func = decorator.decorator
  1217. if func.is_name:
  1218. node.is_classmethod |= func.name == 'classmethod'
  1219. node.is_staticmethod |= func.name == 'staticmethod'
  1220. # transform normal decorators
  1221. decs = node.decorators
  1222. node.decorators = None
  1223. return self.chain_decorators(node, decs, node.name)
  1224. @staticmethod
  1225. def _reject_decorated_property(node, decorator_node):
  1226. # restrict transformation to outermost decorator as wrapped properties will probably not work
  1227. for deco in node.decorators:
  1228. if deco != decorator_node:
  1229. error(deco.pos, "Property methods with additional decorators are not supported")
  1230. return node
  1231. @staticmethod
  1232. def _add_to_property(properties, node, name, decorator):
  1233. prop = properties[node.name]
  1234. node.name = name
  1235. node.decorators.remove(decorator)
  1236. stats = prop.body.stats
  1237. for i, stat in enumerate(stats):
  1238. if stat.name == name:
  1239. stats[i] = node
  1240. break
  1241. else:
  1242. stats.append(node)
  1243. return []
  1244. @staticmethod
  1245. def chain_decorators(node, decorators, name):
  1246. """
  1247. Decorators are applied directly in DefNode and PyClassDefNode to avoid
  1248. reassignments to the function/class name - except for cdef class methods.
  1249. For those, the reassignment is required as methods are originally
  1250. defined in the PyMethodDef struct.
  1251. The IndirectionNode allows DefNode to override the decorator.
  1252. """
  1253. decorator_result = ExprNodes.NameNode(node.pos, name=name)
  1254. for decorator in decorators[::-1]:
  1255. decorator_result = ExprNodes.SimpleCallNode(
  1256. decorator.pos,
  1257. function=decorator.decorator,
  1258. args=[decorator_result])
  1259. name_node = ExprNodes.NameNode(node.pos, name=name)
  1260. reassignment = Nodes.SingleAssignmentNode(
  1261. node.pos,
  1262. lhs=name_node,
  1263. rhs=decorator_result)
  1264. reassignment = Nodes.IndirectionNode([reassignment])
  1265. node.decorator_indirection = reassignment
  1266. return [node, reassignment]
  1267. class CnameDirectivesTransform(CythonTransform, SkipDeclarations):
  1268. """
  1269. Only part of the CythonUtilityCode pipeline. Must be run before
  1270. DecoratorTransform in case this is a decorator for a cdef class.
  1271. It filters out @cname('my_cname') decorators and rewrites them to
  1272. CnameDecoratorNodes.
  1273. """
  1274. def handle_function(self, node):
  1275. if not getattr(node, 'decorators', None):
  1276. return self.visit_Node(node)
  1277. for i, decorator in enumerate(node.decorators):
  1278. decorator = decorator.decorator
  1279. if (isinstance(decorator, ExprNodes.CallNode) and
  1280. decorator.function.is_name and
  1281. decorator.function.name == 'cname'):
  1282. args, kwargs = decorator.explicit_args_kwds()
  1283. if kwargs:
  1284. raise AssertionError(
  1285. "cname decorator does not take keyword arguments")
  1286. if len(args) != 1:
  1287. raise AssertionError(
  1288. "cname decorator takes exactly one argument")
  1289. if not (args[0].is_literal and
  1290. args[0].type == Builtin.str_type):
  1291. raise AssertionError(
  1292. "argument to cname decorator must be a string literal")
  1293. cname = args[0].compile_time_value(None)
  1294. del node.decorators[i]
  1295. node = Nodes.CnameDecoratorNode(pos=node.pos, node=node,
  1296. cname=cname)
  1297. break
  1298. return self.visit_Node(node)
  1299. visit_FuncDefNode = handle_function
  1300. visit_CClassDefNode = handle_function
  1301. visit_CEnumDefNode = handle_function
  1302. visit_CStructOrUnionDefNode = handle_function
  1303. class ForwardDeclareTypes(CythonTransform):
  1304. def visit_CompilerDirectivesNode(self, node):
  1305. env = self.module_scope
  1306. old = env.directives
  1307. env.directives = node.directives
  1308. self.visitchildren(node)
  1309. env.directives = old
  1310. return node
  1311. def visit_ModuleNode(self, node):
  1312. self.module_scope = node.scope
  1313. self.module_scope.directives = node.directives
  1314. self.visitchildren(node)
  1315. return node
  1316. def visit_CDefExternNode(self, node):
  1317. old_cinclude_flag = self.module_scope.in_cinclude
  1318. self.module_scope.in_cinclude = 1
  1319. self.visitchildren(node)
  1320. self.module_scope.in_cinclude = old_cinclude_flag
  1321. return node
  1322. def visit_CEnumDefNode(self, node):
  1323. node.declare(self.module_scope)
  1324. return node
  1325. def visit_CStructOrUnionDefNode(self, node):
  1326. if node.name not in self.module_scope.entries:
  1327. node.declare(self.module_scope)
  1328. return node
  1329. def visit_CClassDefNode(self, node):
  1330. if node.class_name not in self.module_scope.entries:
  1331. node.declare(self.module_scope)
  1332. # Expand fused methods of .pxd declared types to construct the final vtable order.
  1333. type = self.module_scope.entries[node.class_name].type
  1334. if type is not None and type.is_extension_type and not type.is_builtin_type and type.scope:
  1335. scope = type.scope
  1336. for entry in scope.cfunc_entries:
  1337. if entry.type and entry.type.is_fused:
  1338. entry.type.get_all_specialized_function_types()
  1339. return node
  1340. class AnalyseDeclarationsTransform(EnvTransform):
  1341. basic_property = TreeFragment(u"""
  1342. property NAME:
  1343. def __get__(self):
  1344. return ATTR
  1345. def __set__(self, value):
  1346. ATTR = value
  1347. """, level='c_class', pipeline=[NormalizeTree(None)])
  1348. basic_pyobject_property = TreeFragment(u"""
  1349. property NAME:
  1350. def __get__(self):
  1351. return ATTR
  1352. def __set__(self, value):
  1353. ATTR = value
  1354. def __del__(self):
  1355. ATTR = None
  1356. """, level='c_class', pipeline=[NormalizeTree(None)])
  1357. basic_property_ro = TreeFragment(u"""
  1358. property NAME:
  1359. def __get__(self):
  1360. return ATTR
  1361. """, level='c_class', pipeline=[NormalizeTree(None)])
  1362. struct_or_union_wrapper = TreeFragment(u"""
  1363. cdef class NAME:
  1364. cdef TYPE value
  1365. def __init__(self, MEMBER=None):
  1366. cdef int count
  1367. count = 0
  1368. INIT_ASSIGNMENTS
  1369. if IS_UNION and count > 1:
  1370. raise ValueError, "At most one union member should be specified."
  1371. def __str__(self):
  1372. return STR_FORMAT % MEMBER_TUPLE
  1373. def __repr__(self):
  1374. return REPR_FORMAT % MEMBER_TUPLE
  1375. """, pipeline=[NormalizeTree(None)])
  1376. init_assignment = TreeFragment(u"""
  1377. if VALUE is not None:
  1378. ATTR = VALUE
  1379. count += 1
  1380. """, pipeline=[NormalizeTree(None)])
  1381. fused_function = None
  1382. in_lambda = 0
  1383. def __call__(self, root):
  1384. # needed to determine if a cdef var is declared after it's used.
  1385. self.seen_vars_stack = []
  1386. self.fused_error_funcs = set()
  1387. super_class = super(AnalyseDeclarationsTransform, self)
  1388. self._super_visit_FuncDefNode = super_class.visit_FuncDefNode
  1389. return super_class.__call__(root)
  1390. def visit_NameNode(self, node):
  1391. self.seen_vars_stack[-1].add(node.name)
  1392. return node
  1393. def visit_ModuleNode(self, node):
  1394. # Pickling support requires injecting module-level nodes.
  1395. self.extra_module_declarations = []
  1396. self.seen_vars_stack.append(set())
  1397. node.analyse_declarations(self.current_env())
  1398. self.visitchildren(node)
  1399. self.seen_vars_stack.pop()
  1400. node.body.stats.extend(self.extra_module_declarations)
  1401. return node
  1402. def visit_LambdaNode(self, node):
  1403. self.in_lambda += 1
  1404. node.analyse_declarations(self.current_env())
  1405. self.visitchildren(node)
  1406. self.in_lambda -= 1
  1407. return node
  1408. def visit_CClassDefNode(self, node):
  1409. node = self.visit_ClassDefNode(node)
  1410. if node.scope and node.scope.implemented and node.body:
  1411. stats = []
  1412. for entry in node.scope.var_entries:
  1413. if entry.needs_property:
  1414. property = self.create_Property(entry)
  1415. property.analyse_declarations(node.scope)
  1416. self.visit(property)
  1417. stats.append(property)
  1418. if stats:
  1419. node.body.stats += stats
  1420. if (node.visibility != 'extern'
  1421. and not node.scope.lookup('__reduce__')
  1422. and not node.scope.lookup('__reduce_ex__')):
  1423. self._inject_pickle_methods(node)
  1424. return node
  1425. def _inject_pickle_methods(self, node):
  1426. env = self.current_env()
  1427. if node.scope.directives['auto_pickle'] is False: # None means attempt it.
  1428. # Old behavior of not doing anything.
  1429. return
  1430. auto_pickle_forced = node.scope.directives['auto_pickle'] is True
  1431. all_members = []
  1432. cls = node.entry.type
  1433. cinit = None
  1434. inherited_reduce = None
  1435. while cls is not None:
  1436. all_members.extend(e for e in cls.scope.var_entries if e.name not in ('__weakref__', '__dict__'))
  1437. cinit = cinit or cls.scope.lookup('__cinit__')
  1438. inherited_reduce = inherited_reduce or cls.scope.lookup('__reduce__') or cls.scope.lookup('__reduce_ex__')
  1439. cls = cls.base_type
  1440. all_members.sort(key=lambda e: e.name)
  1441. if inherited_reduce:
  1442. # This is not failsafe, as we may not know whether a cimported class defines a __reduce__.
  1443. # This is why we define __reduce_cython__ and only replace __reduce__
  1444. # (via ExtensionTypes.SetupReduce utility code) at runtime on class creation.
  1445. return
  1446. non_py = [
  1447. e for e in all_members
  1448. if not e.type.is_pyobject and (not e.type.can_coerce_to_pyobject(env)
  1449. or not e.type.can_coerce_from_pyobject(env))
  1450. ]
  1451. structs = [e for e in all_members if e.type.is_struct_or_union]
  1452. if cinit or non_py or (structs and not auto_pickle_forced):
  1453. if cinit:
  1454. # TODO(robertwb): We could allow this if __cinit__ has no require arguments.
  1455. msg = 'no default __reduce__ due to non-trivial __cinit__'
  1456. elif non_py:
  1457. msg = "%s cannot be converted to a Python object for pickling" % ','.join("self.%s" % e.name for e in non_py)
  1458. else:
  1459. # Extern structs may be only partially defined.
  1460. # TODO(robertwb): Limit the restriction to extern
  1461. # (and recursively extern-containing) structs.
  1462. msg = ("Pickling of struct members such as %s must be explicitly requested "
  1463. "with @auto_pickle(True)" % ','.join("self.%s" % e.name for e in structs))
  1464. if auto_pickle_forced:
  1465. error(node.pos, msg)
  1466. pickle_func = TreeFragment(u"""
  1467. def __reduce_cython__(self):
  1468. raise TypeError("%(msg)s")
  1469. def __setstate_cython__(self, __pyx_state):
  1470. raise TypeError("%(msg)s")
  1471. """ % {'msg': msg},
  1472. level='c_class', pipeline=[NormalizeTree(None)]).substitute({})
  1473. pickle_func.analyse_declarations(node.scope)
  1474. self.visit(pickle_func)
  1475. node.body.stats.append(pickle_func)
  1476. else:
  1477. for e in all_members:
  1478. if not e.type.is_pyobject:
  1479. e.type.create_to_py_utility_code(env)
  1480. e.type.create_from_py_utility_code(env)
  1481. all_members_names = sorted([e.name for e in all_members])
  1482. checksum = '0x%s' % hashlib.md5(' '.join(all_members_names).encode('utf-8')).hexdigest()[:7]
  1483. unpickle_func_name = '__pyx_unpickle_%s' % node.class_name
  1484. # TODO(robertwb): Move the state into the third argument
  1485. # so it can be pickled *after* self is memoized.
  1486. unpickle_func = TreeFragment(u"""
  1487. def %(unpickle_func_name)s(__pyx_type, long __pyx_checksum, __pyx_state):
  1488. if __pyx_checksum != %(checksum)s:
  1489. from pickle import PickleError as __pyx_PickleError
  1490. raise __pyx_PickleError("Incompatible checksums (%%s vs %(checksum)s = (%(members)s))" %% __pyx_checksum)
  1491. __pyx_result = %(class_name)s.__new__(__pyx_type)
  1492. if __pyx_state is not None:
  1493. %(unpickle_func_name)s__set_state(<%(class_name)s> __pyx_result, __pyx_state)
  1494. return __pyx_result
  1495. cdef %(unpickle_func_name)s__set_state(%(class_name)s __pyx_result, tuple __pyx_state):
  1496. %(assignments)s
  1497. if len(__pyx_state) > %(num_members)d and hasattr(__pyx_result, '__dict__'):
  1498. __pyx_result.__dict__.update(__pyx_state[%(num_members)d])
  1499. """ % {
  1500. 'unpickle_func_name': unpickle_func_name,
  1501. 'checksum': checksum,
  1502. 'members': ', '.join(all_members_names),
  1503. 'class_name': node.class_name,
  1504. 'assignments': '; '.join(
  1505. '__pyx_result.%s = __pyx_state[%s]' % (v, ix)
  1506. for ix, v in enumerate(all_members_names)),
  1507. 'num_members': len(all_members_names),
  1508. }, level='module', pipeline=[NormalizeTree(None)]).substitute({})
  1509. unpickle_func.analyse_declarations(node.entry.scope)
  1510. self.visit(unpickle_func)
  1511. self.extra_module_declarations.append(unpickle_func)
  1512. pickle_func = TreeFragment(u"""
  1513. def __reduce_cython__(self):
  1514. cdef bint use_setstate
  1515. state = (%(members)s)
  1516. _dict = getattr(self, '__dict__', None)
  1517. if _dict is not None:
  1518. state += (_dict,)
  1519. use_setstate = True
  1520. else:
  1521. use_setstate = %(any_notnone_members)s
  1522. if use_setstate:
  1523. return %(unpickle_func_name)s, (type(self), %(checksum)s, None), state
  1524. else:
  1525. return %(unpickle_func_name)s, (type(self), %(checksum)s, state)
  1526. def __setstate_cython__(self, __pyx_state):
  1527. %(unpickle_func_name)s__set_state(self, __pyx_state)
  1528. """ % {
  1529. 'unpickle_func_name': unpickle_func_name,
  1530. 'checksum': checksum,
  1531. 'members': ', '.join('self.%s' % v for v in all_members_names) + (',' if len(all_members_names) == 1 else ''),
  1532. # Even better, we could check PyType_IS_GC.
  1533. 'any_notnone_members' : ' or '.join(['self.%s is not None' % e.name for e in all_members if e.type.is_pyobject] or ['False']),
  1534. },
  1535. level='c_class', pipeline=[NormalizeTree(None)]).substitute({})
  1536. pickle_func.analyse_declarations(node.scope)
  1537. self.visit(pickle_func)
  1538. node.body.stats.append(pickle_func)
  1539. def _handle_fused_def_decorators(self, old_decorators, env, node):
  1540. """
  1541. Create function calls to the decorators and reassignments to
  1542. the function.
  1543. """
  1544. # Delete staticmethod and classmethod decorators, this is
  1545. # handled directly by the fused function object.
  1546. decorators = []
  1547. for decorator in old_decorators:
  1548. func = decorator.decorator
  1549. if (not func.is_name or
  1550. func.name not in ('staticmethod', 'classmethod') or
  1551. env.lookup_here(func.name)):
  1552. # not a static or classmethod
  1553. decorators.append(decorator)
  1554. if decorators:
  1555. transform = DecoratorTransform(self.context)
  1556. def_node = node.node
  1557. _, reassignments = transform.chain_decorators(
  1558. def_node, decorators, def_node.name)
  1559. reassignments.analyse_declarations(env)
  1560. node = [node, reassignments]
  1561. return node
  1562. def _handle_def(self, decorators, env, node):
  1563. "Handle def or cpdef fused functions"
  1564. # Create PyCFunction nodes for each specialization
  1565. node.stats.insert(0, node.py_func)
  1566. node.py_func = self.visit(node.py_func)
  1567. node.update_fused_defnode_entry(env)
  1568. pycfunc = ExprNodes.PyCFunctionNode.from_defnode(node.py_func, binding=True)
  1569. pycfunc = ExprNodes.ProxyNode(pycfunc.coerce_to_temp(env))
  1570. node.resulting_fused_function = pycfunc
  1571. # Create assignment node for our def function
  1572. node.fused_func_assignment = self._create_assignment(
  1573. node.py_func, ExprNodes.CloneNode(pycfunc), env)
  1574. if decorators:
  1575. node = self._handle_fused_def_decorators(decorators, env, node)
  1576. return node
  1577. def _create_fused_function(self, env, node):
  1578. "Create a fused function for a DefNode with fused arguments"
  1579. from . import FusedNode
  1580. if self.fused_function or self.in_lambda:
  1581. if self.fused_function not in self.fused_error_funcs:
  1582. if self.in_lambda:
  1583. error(node.pos, "Fused lambdas not allowed")
  1584. else:
  1585. error(node.pos, "Cannot nest fused functions")
  1586. self.fused_error_funcs.add(self.fused_function)
  1587. node.body = Nodes.PassStatNode(node.pos)
  1588. for arg in node.args:
  1589. if arg.type.is_fused:
  1590. arg.type = arg.type.get_fused_types()[0]
  1591. return node
  1592. decorators = getattr(node, 'decorators', None)
  1593. node = FusedNode.FusedCFuncDefNode(node, env)
  1594. self.fused_function = node
  1595. self.visitchildren(node)
  1596. self.fused_function = None
  1597. if node.py_func:
  1598. node = self._handle_def(decorators, env, node)
  1599. return node
  1600. def _handle_nogil_cleanup(self, lenv, node):
  1601. "Handle cleanup for 'with gil' blocks in nogil functions."
  1602. if lenv.nogil and lenv.has_with_gil_block:
  1603. # Acquire the GIL for cleanup in 'nogil' functions, by wrapping
  1604. # the entire function body in try/finally.
  1605. # The corresponding release will be taken care of by
  1606. # Nodes.FuncDefNode.generate_function_definitions()
  1607. node.body = Nodes.NogilTryFinallyStatNode(
  1608. node.body.pos,
  1609. body=node.body,
  1610. finally_clause=Nodes.EnsureGILNode(node.body.pos),
  1611. finally_except_clause=Nodes.EnsureGILNode(node.body.pos))
  1612. def _handle_fused(self, node):
  1613. if node.is_generator and node.has_fused_arguments:
  1614. node.has_fused_arguments = False
  1615. error(node.pos, "Fused generators not supported")
  1616. node.gbody = Nodes.StatListNode(node.pos,
  1617. stats=[],
  1618. body=Nodes.PassStatNode(node.pos))
  1619. return node.has_fused_arguments
  1620. def visit_FuncDefNode(self, node):
  1621. """
  1622. Analyse a function and its body, as that hasn't happened yet. Also
  1623. analyse the directive_locals set by @cython.locals().
  1624. Then, if we are a function with fused arguments, replace the function
  1625. (after it has declared itself in the symbol table!) with a
  1626. FusedCFuncDefNode, and analyse its children (which are in turn normal
  1627. functions). If we're a normal function, just analyse the body of the
  1628. function.
  1629. """
  1630. env = self.current_env()
  1631. self.seen_vars_stack.append(set())
  1632. lenv = node.local_scope
  1633. node.declare_arguments(lenv)
  1634. # @cython.locals(...)
  1635. for var, type_node in node.directive_locals.items():
  1636. if not lenv.lookup_here(var): # don't redeclare args
  1637. type = type_node.analyse_as_type(lenv)
  1638. if type:
  1639. lenv.declare_var(var, type, type_node.pos)
  1640. else:
  1641. error(type_node.pos, "Not a type")
  1642. if self._handle_fused(node):
  1643. node = self._create_fused_function(env, node)
  1644. else:
  1645. node.body.analyse_declarations(lenv)
  1646. self._handle_nogil_cleanup(lenv, node)
  1647. self._super_visit_FuncDefNode(node)
  1648. self.seen_vars_stack.pop()
  1649. return node
  1650. def visit_DefNode(self, node):
  1651. node = self.visit_FuncDefNode(node)
  1652. env = self.current_env()
  1653. if isinstance(node, Nodes.DefNode) and node.is_wrapper:
  1654. env = env.parent_scope
  1655. if (not isinstance(node, Nodes.DefNode) or
  1656. node.fused_py_func or node.is_generator_body or
  1657. not node.needs_assignment_synthesis(env)):
  1658. return node
  1659. return [node, self._synthesize_assignment(node, env)]
  1660. def visit_GeneratorBodyDefNode(self, node):
  1661. return self.visit_FuncDefNode(node)
  1662. def _synthesize_assignment(self, node, env):
  1663. # Synthesize assignment node and put it right after defnode
  1664. genv = env
  1665. while genv.is_py_class_scope or genv.is_c_class_scope:
  1666. genv = genv.outer_scope
  1667. if genv.is_closure_scope:
  1668. rhs = node.py_cfunc_node = ExprNodes.InnerFunctionNode(
  1669. node.pos, def_node=node,
  1670. pymethdef_cname=node.entry.pymethdef_cname,
  1671. code_object=ExprNodes.CodeObjectNode(node))
  1672. else:
  1673. binding = self.current_directives.get('binding')
  1674. rhs = ExprNodes.PyCFunctionNode.from_defnode(node, binding)
  1675. node.code_object = rhs.code_object
  1676. if node.is_generator:
  1677. node.gbody.code_object = node.code_object
  1678. if env.is_py_class_scope:
  1679. rhs.binding = True
  1680. node.is_cyfunction = rhs.binding
  1681. return self._create_assignment(node, rhs, env)
  1682. def _create_assignment(self, def_node, rhs, env):
  1683. if def_node.decorators:
  1684. for decorator in def_node.decorators[::-1]:
  1685. rhs = ExprNodes.SimpleCallNode(
  1686. decorator.pos,
  1687. function = decorator.decorator,
  1688. args = [rhs])
  1689. def_node.decorators = None
  1690. assmt = Nodes.SingleAssignmentNode(
  1691. def_node.pos,
  1692. lhs=ExprNodes.NameNode(def_node.pos, name=def_node.name),
  1693. rhs=rhs)
  1694. assmt.analyse_declarations(env)
  1695. return assmt
  1696. def visit_ScopedExprNode(self, node):
  1697. env = self.current_env()
  1698. node.analyse_declarations(env)
  1699. # the node may or may not have a local scope
  1700. if node.has_local_scope:
  1701. self.seen_vars_stack.append(set(self.seen_vars_stack[-1]))
  1702. self.enter_scope(node, node.expr_scope)
  1703. node.analyse_scoped_declarations(node.expr_scope)
  1704. self.visitchildren(node)
  1705. self.exit_scope()
  1706. self.seen_vars_stack.pop()
  1707. else:
  1708. node.analyse_scoped_declarations(env)
  1709. self.visitchildren(node)
  1710. return node
  1711. def visit_TempResultFromStatNode(self, node):
  1712. self.visitchildren(node)
  1713. node.analyse_declarations(self.current_env())
  1714. return node
  1715. def visit_CppClassNode(self, node):
  1716. if node.visibility == 'extern':
  1717. return None
  1718. else:
  1719. return self.visit_ClassDefNode(node)
  1720. def visit_CStructOrUnionDefNode(self, node):
  1721. # Create a wrapper node if needed.
  1722. # We want to use the struct type information (so it can't happen
  1723. # before this phase) but also create new objects to be declared
  1724. # (so it can't happen later).
  1725. # Note that we don't return the original node, as it is
  1726. # never used after this phase.
  1727. if True: # private (default)
  1728. return None
  1729. self_value = ExprNodes.AttributeNode(
  1730. pos = node.pos,
  1731. obj = ExprNodes.NameNode(pos=node.pos, name=u"self"),
  1732. attribute = EncodedString(u"value"))
  1733. var_entries = node.entry.type.scope.var_entries
  1734. attributes = []
  1735. for entry in var_entries:
  1736. attributes.append(ExprNodes.AttributeNode(pos = entry.pos,
  1737. obj = self_value,
  1738. attribute = entry.name))
  1739. # __init__ assignments
  1740. init_assignments = []
  1741. for entry, attr in zip(var_entries, attributes):
  1742. # TODO: branch on visibility
  1743. init_assignments.append(self.init_assignment.substitute({
  1744. u"VALUE": ExprNodes.NameNode(entry.pos, name = entry.name),
  1745. u"ATTR": attr,
  1746. }, pos = entry.pos))
  1747. # create the class
  1748. str_format = u"%s(%s)" % (node.entry.type.name, ("%s, " * len(attributes))[:-2])
  1749. wrapper_class = self.struct_or_union_wrapper.substitute({
  1750. u"INIT_ASSIGNMENTS": Nodes.StatListNode(node.pos, stats = init_assignments),
  1751. u"IS_UNION": ExprNodes.BoolNode(node.pos, value = not node.entry.type.is_struct),
  1752. u"MEMBER_TUPLE": ExprNodes.TupleNode(node.pos, args=attributes),
  1753. u"STR_FORMAT": ExprNodes.StringNode(node.pos, value = EncodedString(str_format)),
  1754. u"REPR_FORMAT": ExprNodes.StringNode(node.pos, value = EncodedString(str_format.replace("%s", "%r"))),
  1755. }, pos = node.pos).stats[0]
  1756. wrapper_class.class_name = node.name
  1757. wrapper_class.shadow = True
  1758. class_body = wrapper_class.body.stats
  1759. # fix value type
  1760. assert isinstance(class_body[0].base_type, Nodes.CSimpleBaseTypeNode)
  1761. class_body[0].base_type.name = node.name
  1762. # fix __init__ arguments
  1763. init_method = class_body[1]
  1764. assert isinstance(init_method, Nodes.DefNode) and init_method.name == '__init__'
  1765. arg_template = init_method.args[1]
  1766. if not node.entry.type.is_struct:
  1767. arg_template.kw_only = True
  1768. del init_method.args[1]
  1769. for entry, attr in zip(var_entries, attributes):
  1770. arg = copy.deepcopy(arg_template)
  1771. arg.declarator.name = entry.name
  1772. init_method.args.append(arg)
  1773. # setters/getters
  1774. for entry, attr in zip(var_entries, attributes):
  1775. # TODO: branch on visibility
  1776. if entry.type.is_pyobject:
  1777. template = self.basic_pyobject_property
  1778. else:
  1779. template = self.basic_property
  1780. property = template.substitute({
  1781. u"ATTR": attr,
  1782. }, pos = entry.pos).stats[0]
  1783. property.name = entry.name
  1784. wrapper_class.body.stats.append(property)
  1785. wrapper_class.analyse_declarations(self.current_env())
  1786. return self.visit_CClassDefNode(wrapper_class)
  1787. # Some nodes are no longer needed after declaration
  1788. # analysis and can be dropped. The analysis was performed
  1789. # on these nodes in a separate recursive process from the
  1790. # enclosing function or module, so we can simply drop them.
  1791. def visit_CDeclaratorNode(self, node):
  1792. # necessary to ensure that all CNameDeclaratorNodes are visited.
  1793. self.visitchildren(node)
  1794. return node
  1795. def visit_CTypeDefNode(self, node):
  1796. return node
  1797. def visit_CBaseTypeNode(self, node):
  1798. return None
  1799. def visit_CEnumDefNode(self, node):
  1800. if node.visibility == 'public':
  1801. return node
  1802. else:
  1803. return None
  1804. def visit_CNameDeclaratorNode(self, node):
  1805. if node.name in self.seen_vars_stack[-1]:
  1806. entry = self.current_env().lookup(node.name)
  1807. if (entry is None or entry.visibility != 'extern'
  1808. and not entry.scope.is_c_class_scope):
  1809. warning(node.pos, "cdef variable '%s' declared after it is used" % node.name, 2)
  1810. self.visitchildren(node)
  1811. return node
  1812. def visit_CVarDefNode(self, node):
  1813. # to ensure all CNameDeclaratorNodes are visited.
  1814. self.visitchildren(node)
  1815. return None
  1816. def visit_CnameDecoratorNode(self, node):
  1817. child_node = self.visit(node.node)
  1818. if not child_node:
  1819. return None
  1820. if type(child_node) is list: # Assignment synthesized
  1821. node.child_node = child_node[0]
  1822. return [node] + child_node[1:]
  1823. node.node = child_node
  1824. return node
  1825. def create_Property(self, entry):
  1826. if entry.visibility == 'public':
  1827. if entry.type.is_pyobject:
  1828. template = self.basic_pyobject_property
  1829. else:
  1830. template = self.basic_property
  1831. elif entry.visibility == 'readonly':
  1832. template = self.basic_property_ro
  1833. property = template.substitute({
  1834. u"ATTR": ExprNodes.AttributeNode(pos=entry.pos,
  1835. obj=ExprNodes.NameNode(pos=entry.pos, name="self"),
  1836. attribute=entry.name),
  1837. }, pos=entry.pos).stats[0]
  1838. property.name = entry.name
  1839. property.doc = entry.doc
  1840. return property
  1841. class CalculateQualifiedNamesTransform(EnvTransform):
  1842. """
  1843. Calculate and store the '__qualname__' and the global
  1844. module name on some nodes.
  1845. """
  1846. def visit_ModuleNode(self, node):
  1847. self.module_name = self.global_scope().qualified_name
  1848. self.qualified_name = []
  1849. _super = super(CalculateQualifiedNamesTransform, self)
  1850. self._super_visit_FuncDefNode = _super.visit_FuncDefNode
  1851. self._super_visit_ClassDefNode = _super.visit_ClassDefNode
  1852. self.visitchildren(node)
  1853. return node
  1854. def _set_qualname(self, node, name=None):
  1855. if name:
  1856. qualname = self.qualified_name[:]
  1857. qualname.append(name)
  1858. else:
  1859. qualname = self.qualified_name
  1860. node.qualname = EncodedString('.'.join(qualname))
  1861. node.module_name = self.module_name
  1862. def _append_entry(self, entry):
  1863. if entry.is_pyglobal and not entry.is_pyclass_attr:
  1864. self.qualified_name = [entry.name]
  1865. else:
  1866. self.qualified_name.append(entry.name)
  1867. def visit_ClassNode(self, node):
  1868. self._set_qualname(node, node.name)
  1869. self.visitchildren(node)
  1870. return node
  1871. def visit_PyClassNamespaceNode(self, node):
  1872. # class name was already added by parent node
  1873. self._set_qualname(node)
  1874. self.visitchildren(node)
  1875. return node
  1876. def visit_PyCFunctionNode(self, node):
  1877. orig_qualified_name = self.qualified_name[:]
  1878. if node.def_node.is_wrapper and self.qualified_name and self.qualified_name[-1] == '<locals>':
  1879. self.qualified_name.pop()
  1880. self._set_qualname(node)
  1881. else:
  1882. self._set_qualname(node, node.def_node.name)
  1883. self.visitchildren(node)
  1884. self.qualified_name = orig_qualified_name
  1885. return node
  1886. def visit_DefNode(self, node):
  1887. if node.is_wrapper and self.qualified_name:
  1888. assert self.qualified_name[-1] == '<locals>', self.qualified_name
  1889. orig_qualified_name = self.qualified_name[:]
  1890. self.qualified_name.pop()
  1891. self._set_qualname(node)
  1892. self._super_visit_FuncDefNode(node)
  1893. self.qualified_name = orig_qualified_name
  1894. else:
  1895. self._set_qualname(node, node.name)
  1896. self.visit_FuncDefNode(node)
  1897. return node
  1898. def visit_FuncDefNode(self, node):
  1899. orig_qualified_name = self.qualified_name[:]
  1900. if getattr(node, 'name', None) == '<lambda>':
  1901. self.qualified_name.append('<lambda>')
  1902. else:
  1903. self._append_entry(node.entry)
  1904. self.qualified_name.append('<locals>')
  1905. self._super_visit_FuncDefNode(node)
  1906. self.qualified_name = orig_qualified_name
  1907. return node
  1908. def visit_ClassDefNode(self, node):
  1909. orig_qualified_name = self.qualified_name[:]
  1910. entry = (getattr(node, 'entry', None) or # PyClass
  1911. self.current_env().lookup_here(node.name)) # CClass
  1912. self._append_entry(entry)
  1913. self._super_visit_ClassDefNode(node)
  1914. self.qualified_name = orig_qualified_name
  1915. return node
  1916. class AnalyseExpressionsTransform(CythonTransform):
  1917. def visit_ModuleNode(self, node):
  1918. node.scope.infer_types()
  1919. node.body = node.body.analyse_expressions(node.scope)
  1920. self.visitchildren(node)
  1921. return node
  1922. def visit_FuncDefNode(self, node):
  1923. node.local_scope.infer_types()
  1924. node.body = node.body.analyse_expressions(node.local_scope)
  1925. self.visitchildren(node)
  1926. return node
  1927. def visit_ScopedExprNode(self, node):
  1928. if node.has_local_scope:
  1929. node.expr_scope.infer_types()
  1930. node = node.analyse_scoped_expressions(node.expr_scope)
  1931. self.visitchildren(node)
  1932. return node
  1933. def visit_IndexNode(self, node):
  1934. """
  1935. Replace index nodes used to specialize cdef functions with fused
  1936. argument types with the Attribute- or NameNode referring to the
  1937. function. We then need to copy over the specialization properties to
  1938. the attribute or name node.
  1939. Because the indexing might be a Python indexing operation on a fused
  1940. function, or (usually) a Cython indexing operation, we need to
  1941. re-analyse the types.
  1942. """
  1943. self.visit_Node(node)
  1944. if node.is_fused_index and not node.type.is_error:
  1945. node = node.base
  1946. return node
  1947. class FindInvalidUseOfFusedTypes(CythonTransform):
  1948. def visit_FuncDefNode(self, node):
  1949. # Errors related to use in functions with fused args will already
  1950. # have been detected
  1951. if not node.has_fused_arguments:
  1952. if not node.is_generator_body and node.return_type.is_fused:
  1953. error(node.pos, "Return type is not specified as argument type")
  1954. else:
  1955. self.visitchildren(node)
  1956. return node
  1957. def visit_ExprNode(self, node):
  1958. if node.type and node.type.is_fused:
  1959. error(node.pos, "Invalid use of fused types, type cannot be specialized")
  1960. else:
  1961. self.visitchildren(node)
  1962. return node
  1963. class ExpandInplaceOperators(EnvTransform):
  1964. def visit_InPlaceAssignmentNode(self, node):
  1965. lhs = node.lhs
  1966. rhs = node.rhs
  1967. if lhs.type.is_cpp_class:
  1968. # No getting around this exact operator here.
  1969. return node
  1970. if isinstance(lhs, ExprNodes.BufferIndexNode):
  1971. # There is code to handle this case in InPlaceAssignmentNode
  1972. return node
  1973. env = self.current_env()
  1974. def side_effect_free_reference(node, setting=False):
  1975. if node.is_name:
  1976. return node, []
  1977. elif node.type.is_pyobject and not setting:
  1978. node = LetRefNode(node)
  1979. return node, [node]
  1980. elif node.is_subscript:
  1981. base, temps = side_effect_free_reference(node.base)
  1982. index = LetRefNode(node.index)
  1983. return ExprNodes.IndexNode(node.pos, base=base, index=index), temps + [index]
  1984. elif node.is_attribute:
  1985. obj, temps = side_effect_free_reference(node.obj)
  1986. return ExprNodes.AttributeNode(node.pos, obj=obj, attribute=node.attribute), temps
  1987. elif isinstance(node, ExprNodes.BufferIndexNode):
  1988. raise ValueError("Don't allow things like attributes of buffer indexing operations")
  1989. else:
  1990. node = LetRefNode(node)
  1991. return node, [node]
  1992. try:
  1993. lhs, let_ref_nodes = side_effect_free_reference(lhs, setting=True)
  1994. except ValueError:
  1995. return node
  1996. dup = lhs.__class__(**lhs.__dict__)
  1997. binop = ExprNodes.binop_node(node.pos,
  1998. operator = node.operator,
  1999. operand1 = dup,
  2000. operand2 = rhs,
  2001. inplace=True)
  2002. # Manually analyse types for new node.
  2003. lhs.analyse_target_types(env)
  2004. dup.analyse_types(env)
  2005. binop.analyse_operation(env)
  2006. node = Nodes.SingleAssignmentNode(
  2007. node.pos,
  2008. lhs = lhs,
  2009. rhs=binop.coerce_to(lhs.type, env))
  2010. # Use LetRefNode to avoid side effects.
  2011. let_ref_nodes.reverse()
  2012. for t in let_ref_nodes:
  2013. node = LetNode(t, node)
  2014. return node
  2015. def visit_ExprNode(self, node):
  2016. # In-place assignments can't happen within an expression.
  2017. return node
  2018. class AdjustDefByDirectives(CythonTransform, SkipDeclarations):
  2019. """
  2020. Adjust function and class definitions by the decorator directives:
  2021. @cython.cfunc
  2022. @cython.cclass
  2023. @cython.ccall
  2024. @cython.inline
  2025. """
  2026. def visit_ModuleNode(self, node):
  2027. self.directives = node.directives
  2028. self.in_py_class = False
  2029. self.visitchildren(node)
  2030. return node
  2031. def visit_CompilerDirectivesNode(self, node):
  2032. old_directives = self.directives
  2033. self.directives = node.directives
  2034. self.visitchildren(node)
  2035. self.directives = old_directives
  2036. return node
  2037. def visit_DefNode(self, node):
  2038. modifiers = []
  2039. if 'inline' in self.directives:
  2040. modifiers.append('inline')
  2041. except_val = self.directives.get('exceptval')
  2042. return_type_node = self.directives.get('returns')
  2043. if return_type_node is None and self.directives['annotation_typing']:
  2044. return_type_node = node.return_type_annotation
  2045. # for Python anntations, prefer safe exception handling by default
  2046. if return_type_node is not None and except_val is None:
  2047. except_val = (None, True) # except *
  2048. elif except_val is None:
  2049. # backward compatible default: no exception check
  2050. except_val = (None, False)
  2051. if 'ccall' in self.directives:
  2052. node = node.as_cfunction(
  2053. overridable=True, modifiers=modifiers,
  2054. returns=return_type_node, except_val=except_val)
  2055. return self.visit(node)
  2056. if 'cfunc' in self.directives:
  2057. if self.in_py_class:
  2058. error(node.pos, "cfunc directive is not allowed here")
  2059. else:
  2060. node = node.as_cfunction(
  2061. overridable=False, modifiers=modifiers,
  2062. returns=return_type_node, except_val=except_val)
  2063. return self.visit(node)
  2064. if 'inline' in modifiers:
  2065. error(node.pos, "Python functions cannot be declared 'inline'")
  2066. self.visitchildren(node)
  2067. return node
  2068. def visit_PyClassDefNode(self, node):
  2069. if 'cclass' in self.directives:
  2070. node = node.as_cclass()
  2071. return self.visit(node)
  2072. else:
  2073. old_in_pyclass = self.in_py_class
  2074. self.in_py_class = True
  2075. self.visitchildren(node)
  2076. self.in_py_class = old_in_pyclass
  2077. return node
  2078. def visit_CClassDefNode(self, node):
  2079. old_in_pyclass = self.in_py_class
  2080. self.in_py_class = False
  2081. self.visitchildren(node)
  2082. self.in_py_class = old_in_pyclass
  2083. return node
  2084. class AlignFunctionDefinitions(CythonTransform):
  2085. """
  2086. This class takes the signatures from a .pxd file and applies them to
  2087. the def methods in a .py file.
  2088. """
  2089. def visit_ModuleNode(self, node):
  2090. self.scope = node.scope
  2091. self.directives = node.directives
  2092. self.imported_names = set() # hack, see visit_FromImportStatNode()
  2093. self.visitchildren(node)
  2094. return node
  2095. def visit_PyClassDefNode(self, node):
  2096. pxd_def = self.scope.lookup(node.name)
  2097. if pxd_def:
  2098. if pxd_def.is_cclass:
  2099. return self.visit_CClassDefNode(node.as_cclass(), pxd_def)
  2100. elif not pxd_def.scope or not pxd_def.scope.is_builtin_scope:
  2101. error(node.pos, "'%s' redeclared" % node.name)
  2102. if pxd_def.pos:
  2103. error(pxd_def.pos, "previous declaration here")
  2104. return None
  2105. return node
  2106. def visit_CClassDefNode(self, node, pxd_def=None):
  2107. if pxd_def is None:
  2108. pxd_def = self.scope.lookup(node.class_name)
  2109. if pxd_def:
  2110. if not pxd_def.defined_in_pxd:
  2111. return node
  2112. outer_scope = self.scope
  2113. self.scope = pxd_def.type.scope
  2114. self.visitchildren(node)
  2115. if pxd_def:
  2116. self.scope = outer_scope
  2117. return node
  2118. def visit_DefNode(self, node):
  2119. pxd_def = self.scope.lookup(node.name)
  2120. if pxd_def and (not pxd_def.scope or not pxd_def.scope.is_builtin_scope):
  2121. if not pxd_def.is_cfunction:
  2122. error(node.pos, "'%s' redeclared" % node.name)
  2123. if pxd_def.pos:
  2124. error(pxd_def.pos, "previous declaration here")
  2125. return None
  2126. node = node.as_cfunction(pxd_def)
  2127. elif (self.scope.is_module_scope and self.directives['auto_cpdef']
  2128. and not node.name in self.imported_names
  2129. and node.is_cdef_func_compatible()):
  2130. # FIXME: cpdef-ing should be done in analyse_declarations()
  2131. node = node.as_cfunction(scope=self.scope)
  2132. # Enable this when nested cdef functions are allowed.
  2133. # self.visitchildren(node)
  2134. return node
  2135. def visit_FromImportStatNode(self, node):
  2136. # hack to prevent conditional import fallback functions from
  2137. # being cdpef-ed (global Python variables currently conflict
  2138. # with imports)
  2139. if self.scope.is_module_scope:
  2140. for name, _ in node.items:
  2141. self.imported_names.add(name)
  2142. return node
  2143. def visit_ExprNode(self, node):
  2144. # ignore lambdas and everything else that appears in expressions
  2145. return node
  2146. class RemoveUnreachableCode(CythonTransform):
  2147. def visit_StatListNode(self, node):
  2148. if not self.current_directives['remove_unreachable']:
  2149. return node
  2150. self.visitchildren(node)
  2151. for idx, stat in enumerate(node.stats):
  2152. idx += 1
  2153. if stat.is_terminator:
  2154. if idx < len(node.stats):
  2155. if self.current_directives['warn.unreachable']:
  2156. warning(node.stats[idx].pos, "Unreachable code", 2)
  2157. node.stats = node.stats[:idx]
  2158. node.is_terminator = True
  2159. break
  2160. return node
  2161. def visit_IfClauseNode(self, node):
  2162. self.visitchildren(node)
  2163. if node.body.is_terminator:
  2164. node.is_terminator = True
  2165. return node
  2166. def visit_IfStatNode(self, node):
  2167. self.visitchildren(node)
  2168. if node.else_clause and node.else_clause.is_terminator:
  2169. for clause in node.if_clauses:
  2170. if not clause.is_terminator:
  2171. break
  2172. else:
  2173. node.is_terminator = True
  2174. return node
  2175. def visit_TryExceptStatNode(self, node):
  2176. self.visitchildren(node)
  2177. if node.body.is_terminator and node.else_clause:
  2178. if self.current_directives['warn.unreachable']:
  2179. warning(node.else_clause.pos, "Unreachable code", 2)
  2180. node.else_clause = None
  2181. return node
  2182. class YieldNodeCollector(TreeVisitor):
  2183. def __init__(self):
  2184. super(YieldNodeCollector, self).__init__()
  2185. self.yields = []
  2186. self.returns = []
  2187. self.finallys = []
  2188. self.excepts = []
  2189. self.has_return_value = False
  2190. self.has_yield = False
  2191. self.has_await = False
  2192. def visit_Node(self, node):
  2193. self.visitchildren(node)
  2194. def visit_YieldExprNode(self, node):
  2195. self.yields.append(node)
  2196. self.has_yield = True
  2197. self.visitchildren(node)
  2198. def visit_AwaitExprNode(self, node):
  2199. self.yields.append(node)
  2200. self.has_await = True
  2201. self.visitchildren(node)
  2202. def visit_ReturnStatNode(self, node):
  2203. self.visitchildren(node)
  2204. if node.value:
  2205. self.has_return_value = True
  2206. self.returns.append(node)
  2207. def visit_TryFinallyStatNode(self, node):
  2208. self.visitchildren(node)
  2209. self.finallys.append(node)
  2210. def visit_TryExceptStatNode(self, node):
  2211. self.visitchildren(node)
  2212. self.excepts.append(node)
  2213. def visit_ClassDefNode(self, node):
  2214. pass
  2215. def visit_FuncDefNode(self, node):
  2216. pass
  2217. def visit_LambdaNode(self, node):
  2218. pass
  2219. def visit_GeneratorExpressionNode(self, node):
  2220. pass
  2221. def visit_CArgDeclNode(self, node):
  2222. # do not look into annotations
  2223. # FIXME: support (yield) in default arguments (currently crashes)
  2224. pass
  2225. class MarkClosureVisitor(CythonTransform):
  2226. def visit_ModuleNode(self, node):
  2227. self.needs_closure = False
  2228. self.visitchildren(node)
  2229. return node
  2230. def visit_FuncDefNode(self, node):
  2231. self.needs_closure = False
  2232. self.visitchildren(node)
  2233. node.needs_closure = self.needs_closure
  2234. self.needs_closure = True
  2235. collector = YieldNodeCollector()
  2236. collector.visitchildren(node)
  2237. if node.is_async_def:
  2238. coroutine_type = Nodes.AsyncDefNode
  2239. if collector.has_yield:
  2240. coroutine_type = Nodes.AsyncGenNode
  2241. for yield_expr in collector.yields + collector.returns:
  2242. yield_expr.in_async_gen = True
  2243. elif self.current_directives['iterable_coroutine']:
  2244. coroutine_type = Nodes.IterableAsyncDefNode
  2245. elif collector.has_await:
  2246. found = next(y for y in collector.yields if y.is_await)
  2247. error(found.pos, "'await' not allowed in generators (use 'yield')")
  2248. return node
  2249. elif collector.has_yield:
  2250. coroutine_type = Nodes.GeneratorDefNode
  2251. else:
  2252. return node
  2253. for i, yield_expr in enumerate(collector.yields, 1):
  2254. yield_expr.label_num = i
  2255. for retnode in collector.returns + collector.finallys + collector.excepts:
  2256. retnode.in_generator = True
  2257. gbody = Nodes.GeneratorBodyDefNode(
  2258. pos=node.pos, name=node.name, body=node.body,
  2259. is_async_gen_body=node.is_async_def and collector.has_yield)
  2260. coroutine = coroutine_type(
  2261. pos=node.pos, name=node.name, args=node.args,
  2262. star_arg=node.star_arg, starstar_arg=node.starstar_arg,
  2263. doc=node.doc, decorators=node.decorators,
  2264. gbody=gbody, lambda_name=node.lambda_name)
  2265. return coroutine
  2266. def visit_CFuncDefNode(self, node):
  2267. self.needs_closure = False
  2268. self.visitchildren(node)
  2269. node.needs_closure = self.needs_closure
  2270. self.needs_closure = True
  2271. if node.needs_closure and node.overridable:
  2272. error(node.pos, "closures inside cpdef functions not yet supported")
  2273. return node
  2274. def visit_LambdaNode(self, node):
  2275. self.needs_closure = False
  2276. self.visitchildren(node)
  2277. node.needs_closure = self.needs_closure
  2278. self.needs_closure = True
  2279. return node
  2280. def visit_ClassDefNode(self, node):
  2281. self.visitchildren(node)
  2282. self.needs_closure = True
  2283. return node
  2284. class CreateClosureClasses(CythonTransform):
  2285. # Output closure classes in module scope for all functions
  2286. # that really need it.
  2287. def __init__(self, context):
  2288. super(CreateClosureClasses, self).__init__(context)
  2289. self.path = []
  2290. self.in_lambda = False
  2291. def visit_ModuleNode(self, node):
  2292. self.module_scope = node.scope
  2293. self.visitchildren(node)
  2294. return node
  2295. def find_entries_used_in_closures(self, node):
  2296. from_closure = []
  2297. in_closure = []
  2298. for scope in node.local_scope.iter_local_scopes():
  2299. for name, entry in scope.entries.items():
  2300. if not name:
  2301. continue
  2302. if entry.from_closure:
  2303. from_closure.append((name, entry))
  2304. elif entry.in_closure:
  2305. in_closure.append((name, entry))
  2306. return from_closure, in_closure
  2307. def create_class_from_scope(self, node, target_module_scope, inner_node=None):
  2308. # move local variables into closure
  2309. if node.is_generator:
  2310. for scope in node.local_scope.iter_local_scopes():
  2311. for entry in scope.entries.values():
  2312. if not entry.from_closure:
  2313. entry.in_closure = True
  2314. from_closure, in_closure = self.find_entries_used_in_closures(node)
  2315. in_closure.sort()
  2316. # Now from the beginning
  2317. node.needs_closure = False
  2318. node.needs_outer_scope = False
  2319. func_scope = node.local_scope
  2320. cscope = node.entry.scope
  2321. while cscope.is_py_class_scope or cscope.is_c_class_scope:
  2322. cscope = cscope.outer_scope
  2323. if not from_closure and (self.path or inner_node):
  2324. if not inner_node:
  2325. if not node.py_cfunc_node:
  2326. raise InternalError("DefNode does not have assignment node")
  2327. inner_node = node.py_cfunc_node
  2328. inner_node.needs_self_code = False
  2329. node.needs_outer_scope = False
  2330. if node.is_generator:
  2331. pass
  2332. elif not in_closure and not from_closure:
  2333. return
  2334. elif not in_closure:
  2335. func_scope.is_passthrough = True
  2336. func_scope.scope_class = cscope.scope_class
  2337. node.needs_outer_scope = True
  2338. return
  2339. as_name = '%s_%s' % (
  2340. target_module_scope.next_id(Naming.closure_class_prefix),
  2341. node.entry.cname)
  2342. entry = target_module_scope.declare_c_class(
  2343. name=as_name, pos=node.pos, defining=True,
  2344. implementing=True)
  2345. entry.type.is_final_type = True
  2346. func_scope.scope_class = entry
  2347. class_scope = entry.type.scope
  2348. class_scope.is_internal = True
  2349. class_scope.is_closure_class_scope = True
  2350. if node.is_async_def or node.is_generator:
  2351. # Generators need their closure intact during cleanup as they resume to handle GeneratorExit
  2352. class_scope.directives['no_gc_clear'] = True
  2353. if Options.closure_freelist_size:
  2354. class_scope.directives['freelist'] = Options.closure_freelist_size
  2355. if from_closure:
  2356. assert cscope.is_closure_scope
  2357. class_scope.declare_var(pos=node.pos,
  2358. name=Naming.outer_scope_cname,
  2359. cname=Naming.outer_scope_cname,
  2360. type=cscope.scope_class.type,
  2361. is_cdef=True)
  2362. node.needs_outer_scope = True
  2363. for name, entry in in_closure:
  2364. closure_entry = class_scope.declare_var(
  2365. pos=entry.pos,
  2366. name=entry.name if not entry.in_subscope else None,
  2367. cname=entry.cname,
  2368. type=entry.type,
  2369. is_cdef=True)
  2370. if entry.is_declared_generic:
  2371. closure_entry.is_declared_generic = 1
  2372. node.needs_closure = True
  2373. # Do it here because other classes are already checked
  2374. target_module_scope.check_c_class(func_scope.scope_class)
  2375. def visit_LambdaNode(self, node):
  2376. if not isinstance(node.def_node, Nodes.DefNode):
  2377. # fused function, an error has been previously issued
  2378. return node
  2379. was_in_lambda = self.in_lambda
  2380. self.in_lambda = True
  2381. self.create_class_from_scope(node.def_node, self.module_scope, node)
  2382. self.visitchildren(node)
  2383. self.in_lambda = was_in_lambda
  2384. return node
  2385. def visit_FuncDefNode(self, node):
  2386. if self.in_lambda:
  2387. self.visitchildren(node)
  2388. return node
  2389. if node.needs_closure or self.path:
  2390. self.create_class_from_scope(node, self.module_scope)
  2391. self.path.append(node)
  2392. self.visitchildren(node)
  2393. self.path.pop()
  2394. return node
  2395. def visit_GeneratorBodyDefNode(self, node):
  2396. self.visitchildren(node)
  2397. return node
  2398. def visit_CFuncDefNode(self, node):
  2399. if not node.overridable:
  2400. return self.visit_FuncDefNode(node)
  2401. else:
  2402. self.visitchildren(node)
  2403. return node
  2404. class GilCheck(VisitorTransform):
  2405. """
  2406. Call `node.gil_check(env)` on each node to make sure we hold the
  2407. GIL when we need it. Raise an error when on Python operations
  2408. inside a `nogil` environment.
  2409. Additionally, raise exceptions for closely nested with gil or with nogil
  2410. statements. The latter would abort Python.
  2411. """
  2412. def __call__(self, root):
  2413. self.env_stack = [root.scope]
  2414. self.nogil = False
  2415. # True for 'cdef func() nogil:' functions, as the GIL may be held while
  2416. # calling this function (thus contained 'nogil' blocks may be valid).
  2417. self.nogil_declarator_only = False
  2418. return super(GilCheck, self).__call__(root)
  2419. def visit_FuncDefNode(self, node):
  2420. self.env_stack.append(node.local_scope)
  2421. was_nogil = self.nogil
  2422. self.nogil = node.local_scope.nogil
  2423. if self.nogil:
  2424. self.nogil_declarator_only = True
  2425. if self.nogil and node.nogil_check:
  2426. node.nogil_check(node.local_scope)
  2427. self.visitchildren(node)
  2428. # This cannot be nested, so it doesn't need backup/restore
  2429. self.nogil_declarator_only = False
  2430. self.env_stack.pop()
  2431. self.nogil = was_nogil
  2432. return node
  2433. def visit_GILStatNode(self, node):
  2434. if self.nogil and node.nogil_check:
  2435. node.nogil_check()
  2436. was_nogil = self.nogil
  2437. self.nogil = (node.state == 'nogil')
  2438. if was_nogil == self.nogil and not self.nogil_declarator_only:
  2439. if not was_nogil:
  2440. error(node.pos, "Trying to acquire the GIL while it is "
  2441. "already held.")
  2442. else:
  2443. error(node.pos, "Trying to release the GIL while it was "
  2444. "previously released.")
  2445. if isinstance(node.finally_clause, Nodes.StatListNode):
  2446. # The finally clause of the GILStatNode is a GILExitNode,
  2447. # which is wrapped in a StatListNode. Just unpack that.
  2448. node.finally_clause, = node.finally_clause.stats
  2449. self.visitchildren(node)
  2450. self.nogil = was_nogil
  2451. return node
  2452. def visit_ParallelRangeNode(self, node):
  2453. if node.nogil:
  2454. node.nogil = False
  2455. node = Nodes.GILStatNode(node.pos, state='nogil', body=node)
  2456. return self.visit_GILStatNode(node)
  2457. if not self.nogil:
  2458. error(node.pos, "prange() can only be used without the GIL")
  2459. # Forget about any GIL-related errors that may occur in the body
  2460. return None
  2461. node.nogil_check(self.env_stack[-1])
  2462. self.visitchildren(node)
  2463. return node
  2464. def visit_ParallelWithBlockNode(self, node):
  2465. if not self.nogil:
  2466. error(node.pos, "The parallel section may only be used without "
  2467. "the GIL")
  2468. return None
  2469. if node.nogil_check:
  2470. # It does not currently implement this, but test for it anyway to
  2471. # avoid potential future surprises
  2472. node.nogil_check(self.env_stack[-1])
  2473. self.visitchildren(node)
  2474. return node
  2475. def visit_TryFinallyStatNode(self, node):
  2476. """
  2477. Take care of try/finally statements in nogil code sections.
  2478. """
  2479. if not self.nogil or isinstance(node, Nodes.GILStatNode):
  2480. return self.visit_Node(node)
  2481. node.nogil_check = None
  2482. node.is_try_finally_in_nogil = True
  2483. self.visitchildren(node)
  2484. return node
  2485. def visit_Node(self, node):
  2486. if self.env_stack and self.nogil and node.nogil_check:
  2487. node.nogil_check(self.env_stack[-1])
  2488. self.visitchildren(node)
  2489. node.in_nogil_context = self.nogil
  2490. return node
  2491. class TransformBuiltinMethods(EnvTransform):
  2492. """
  2493. Replace Cython's own cython.* builtins by the corresponding tree nodes.
  2494. """
  2495. def visit_SingleAssignmentNode(self, node):
  2496. if node.declaration_only:
  2497. return None
  2498. else:
  2499. self.visitchildren(node)
  2500. return node
  2501. def visit_AttributeNode(self, node):
  2502. self.visitchildren(node)
  2503. return self.visit_cython_attribute(node)
  2504. def visit_NameNode(self, node):
  2505. return self.visit_cython_attribute(node)
  2506. def visit_cython_attribute(self, node):
  2507. attribute = node.as_cython_attribute()
  2508. if attribute:
  2509. if attribute == u'compiled':
  2510. node = ExprNodes.BoolNode(node.pos, value=True)
  2511. elif attribute == u'__version__':
  2512. from .. import __version__ as version
  2513. node = ExprNodes.StringNode(node.pos, value=EncodedString(version))
  2514. elif attribute == u'NULL':
  2515. node = ExprNodes.NullNode(node.pos)
  2516. elif attribute in (u'set', u'frozenset', u'staticmethod'):
  2517. node = ExprNodes.NameNode(node.pos, name=EncodedString(attribute),
  2518. entry=self.current_env().builtin_scope().lookup_here(attribute))
  2519. elif PyrexTypes.parse_basic_type(attribute):
  2520. pass
  2521. elif self.context.cython_scope.lookup_qualified_name(attribute):
  2522. pass
  2523. else:
  2524. error(node.pos, u"'%s' not a valid cython attribute or is being used incorrectly" % attribute)
  2525. return node
  2526. def visit_ExecStatNode(self, node):
  2527. lenv = self.current_env()
  2528. self.visitchildren(node)
  2529. if len(node.args) == 1:
  2530. node.args.append(ExprNodes.GlobalsExprNode(node.pos))
  2531. if not lenv.is_module_scope:
  2532. node.args.append(
  2533. ExprNodes.LocalsExprNode(
  2534. node.pos, self.current_scope_node(), lenv))
  2535. return node
  2536. def _inject_locals(self, node, func_name):
  2537. # locals()/dir()/vars() builtins
  2538. lenv = self.current_env()
  2539. entry = lenv.lookup_here(func_name)
  2540. if entry:
  2541. # not the builtin
  2542. return node
  2543. pos = node.pos
  2544. if func_name in ('locals', 'vars'):
  2545. if func_name == 'locals' and len(node.args) > 0:
  2546. error(self.pos, "Builtin 'locals()' called with wrong number of args, expected 0, got %d"
  2547. % len(node.args))
  2548. return node
  2549. elif func_name == 'vars':
  2550. if len(node.args) > 1:
  2551. error(self.pos, "Builtin 'vars()' called with wrong number of args, expected 0-1, got %d"
  2552. % len(node.args))
  2553. if len(node.args) > 0:
  2554. return node # nothing to do
  2555. return ExprNodes.LocalsExprNode(pos, self.current_scope_node(), lenv)
  2556. else: # dir()
  2557. if len(node.args) > 1:
  2558. error(self.pos, "Builtin 'dir()' called with wrong number of args, expected 0-1, got %d"
  2559. % len(node.args))
  2560. if len(node.args) > 0:
  2561. # optimised in Builtin.py
  2562. return node
  2563. if lenv.is_py_class_scope or lenv.is_module_scope:
  2564. if lenv.is_py_class_scope:
  2565. pyclass = self.current_scope_node()
  2566. locals_dict = ExprNodes.CloneNode(pyclass.dict)
  2567. else:
  2568. locals_dict = ExprNodes.GlobalsExprNode(pos)
  2569. return ExprNodes.SortedDictKeysNode(locals_dict)
  2570. local_names = sorted(var.name for var in lenv.entries.values() if var.name)
  2571. items = [ExprNodes.IdentifierStringNode(pos, value=var)
  2572. for var in local_names]
  2573. return ExprNodes.ListNode(pos, args=items)
  2574. def visit_PrimaryCmpNode(self, node):
  2575. # special case: for in/not-in test, we do not need to sort locals()
  2576. self.visitchildren(node)
  2577. if node.operator in 'not_in': # in/not_in
  2578. if isinstance(node.operand2, ExprNodes.SortedDictKeysNode):
  2579. arg = node.operand2.arg
  2580. if isinstance(arg, ExprNodes.NoneCheckNode):
  2581. arg = arg.arg
  2582. node.operand2 = arg
  2583. return node
  2584. def visit_CascadedCmpNode(self, node):
  2585. return self.visit_PrimaryCmpNode(node)
  2586. def _inject_eval(self, node, func_name):
  2587. lenv = self.current_env()
  2588. entry = lenv.lookup_here(func_name)
  2589. if entry or len(node.args) != 1:
  2590. return node
  2591. # Inject globals and locals
  2592. node.args.append(ExprNodes.GlobalsExprNode(node.pos))
  2593. if not lenv.is_module_scope:
  2594. node.args.append(
  2595. ExprNodes.LocalsExprNode(
  2596. node.pos, self.current_scope_node(), lenv))
  2597. return node
  2598. def _inject_super(self, node, func_name):
  2599. lenv = self.current_env()
  2600. entry = lenv.lookup_here(func_name)
  2601. if entry or node.args:
  2602. return node
  2603. # Inject no-args super
  2604. def_node = self.current_scope_node()
  2605. if (not isinstance(def_node, Nodes.DefNode) or not def_node.args or
  2606. len(self.env_stack) < 2):
  2607. return node
  2608. class_node, class_scope = self.env_stack[-2]
  2609. if class_scope.is_py_class_scope:
  2610. def_node.requires_classobj = True
  2611. class_node.class_cell.is_active = True
  2612. node.args = [
  2613. ExprNodes.ClassCellNode(
  2614. node.pos, is_generator=def_node.is_generator),
  2615. ExprNodes.NameNode(node.pos, name=def_node.args[0].name)
  2616. ]
  2617. elif class_scope.is_c_class_scope:
  2618. node.args = [
  2619. ExprNodes.NameNode(
  2620. node.pos, name=class_node.scope.name,
  2621. entry=class_node.entry),
  2622. ExprNodes.NameNode(node.pos, name=def_node.args[0].name)
  2623. ]
  2624. return node
  2625. def visit_SimpleCallNode(self, node):
  2626. # cython.foo
  2627. function = node.function.as_cython_attribute()
  2628. if function:
  2629. if function in InterpretCompilerDirectives.unop_method_nodes:
  2630. if len(node.args) != 1:
  2631. error(node.function.pos, u"%s() takes exactly one argument" % function)
  2632. else:
  2633. node = InterpretCompilerDirectives.unop_method_nodes[function](
  2634. node.function.pos, operand=node.args[0])
  2635. elif function in InterpretCompilerDirectives.binop_method_nodes:
  2636. if len(node.args) != 2:
  2637. error(node.function.pos, u"%s() takes exactly two arguments" % function)
  2638. else:
  2639. node = InterpretCompilerDirectives.binop_method_nodes[function](
  2640. node.function.pos, operand1=node.args[0], operand2=node.args[1])
  2641. elif function == u'cast':
  2642. if len(node.args) != 2:
  2643. error(node.function.pos,
  2644. u"cast() takes exactly two arguments and an optional typecheck keyword")
  2645. else:
  2646. type = node.args[0].analyse_as_type(self.current_env())
  2647. if type:
  2648. node = ExprNodes.TypecastNode(
  2649. node.function.pos, type=type, operand=node.args[1], typecheck=False)
  2650. else:
  2651. error(node.args[0].pos, "Not a type")
  2652. elif function == u'sizeof':
  2653. if len(node.args) != 1:
  2654. error(node.function.pos, u"sizeof() takes exactly one argument")
  2655. else:
  2656. type = node.args[0].analyse_as_type(self.current_env())
  2657. if type:
  2658. node = ExprNodes.SizeofTypeNode(node.function.pos, arg_type=type)
  2659. else:
  2660. node = ExprNodes.SizeofVarNode(node.function.pos, operand=node.args[0])
  2661. elif function == 'cmod':
  2662. if len(node.args) != 2:
  2663. error(node.function.pos, u"cmod() takes exactly two arguments")
  2664. else:
  2665. node = ExprNodes.binop_node(node.function.pos, '%', node.args[0], node.args[1])
  2666. node.cdivision = True
  2667. elif function == 'cdiv':
  2668. if len(node.args) != 2:
  2669. error(node.function.pos, u"cdiv() takes exactly two arguments")
  2670. else:
  2671. node = ExprNodes.binop_node(node.function.pos, '/', node.args[0], node.args[1])
  2672. node.cdivision = True
  2673. elif function == u'set':
  2674. node.function = ExprNodes.NameNode(node.pos, name=EncodedString('set'))
  2675. elif function == u'staticmethod':
  2676. node.function = ExprNodes.NameNode(node.pos, name=EncodedString('staticmethod'))
  2677. elif self.context.cython_scope.lookup_qualified_name(function):
  2678. pass
  2679. else:
  2680. error(node.function.pos,
  2681. u"'%s' not a valid cython language construct" % function)
  2682. self.visitchildren(node)
  2683. if isinstance(node, ExprNodes.SimpleCallNode) and node.function.is_name:
  2684. func_name = node.function.name
  2685. if func_name in ('dir', 'locals', 'vars'):
  2686. return self._inject_locals(node, func_name)
  2687. if func_name == 'eval':
  2688. return self._inject_eval(node, func_name)
  2689. if func_name == 'super':
  2690. return self._inject_super(node, func_name)
  2691. return node
  2692. def visit_GeneralCallNode(self, node):
  2693. function = node.function.as_cython_attribute()
  2694. if function == u'cast':
  2695. # NOTE: assuming simple tuple/dict nodes for positional_args and keyword_args
  2696. args = node.positional_args.args
  2697. kwargs = node.keyword_args.compile_time_value(None)
  2698. if (len(args) != 2 or len(kwargs) > 1 or
  2699. (len(kwargs) == 1 and 'typecheck' not in kwargs)):
  2700. error(node.function.pos,
  2701. u"cast() takes exactly two arguments and an optional typecheck keyword")
  2702. else:
  2703. type = args[0].analyse_as_type(self.current_env())
  2704. if type:
  2705. typecheck = kwargs.get('typecheck', False)
  2706. node = ExprNodes.TypecastNode(
  2707. node.function.pos, type=type, operand=args[1], typecheck=typecheck)
  2708. else:
  2709. error(args[0].pos, "Not a type")
  2710. self.visitchildren(node)
  2711. return node
  2712. class ReplaceFusedTypeChecks(VisitorTransform):
  2713. """
  2714. This is not a transform in the pipeline. It is invoked on the specific
  2715. versions of a cdef function with fused argument types. It filters out any
  2716. type branches that don't match. e.g.
  2717. if fused_t is mytype:
  2718. ...
  2719. elif fused_t in other_fused_type:
  2720. ...
  2721. """
  2722. def __init__(self, local_scope):
  2723. super(ReplaceFusedTypeChecks, self).__init__()
  2724. self.local_scope = local_scope
  2725. # defer the import until now to avoid circular import time dependencies
  2726. from .Optimize import ConstantFolding
  2727. self.transform = ConstantFolding(reevaluate=True)
  2728. def visit_IfStatNode(self, node):
  2729. """
  2730. Filters out any if clauses with false compile time type check
  2731. expression.
  2732. """
  2733. self.visitchildren(node)
  2734. return self.transform(node)
  2735. def visit_PrimaryCmpNode(self, node):
  2736. with Errors.local_errors(ignore=True):
  2737. type1 = node.operand1.analyse_as_type(self.local_scope)
  2738. type2 = node.operand2.analyse_as_type(self.local_scope)
  2739. if type1 and type2:
  2740. false_node = ExprNodes.BoolNode(node.pos, value=False)
  2741. true_node = ExprNodes.BoolNode(node.pos, value=True)
  2742. type1 = self.specialize_type(type1, node.operand1.pos)
  2743. op = node.operator
  2744. if op in ('is', 'is_not', '==', '!='):
  2745. type2 = self.specialize_type(type2, node.operand2.pos)
  2746. is_same = type1.same_as(type2)
  2747. eq = op in ('is', '==')
  2748. if (is_same and eq) or (not is_same and not eq):
  2749. return true_node
  2750. elif op in ('in', 'not_in'):
  2751. # We have to do an instance check directly, as operand2
  2752. # needs to be a fused type and not a type with a subtype
  2753. # that is fused. First unpack the typedef
  2754. if isinstance(type2, PyrexTypes.CTypedefType):
  2755. type2 = type2.typedef_base_type
  2756. if type1.is_fused:
  2757. error(node.operand1.pos, "Type is fused")
  2758. elif not type2.is_fused:
  2759. error(node.operand2.pos,
  2760. "Can only use 'in' or 'not in' on a fused type")
  2761. else:
  2762. types = PyrexTypes.get_specialized_types(type2)
  2763. for specialized_type in types:
  2764. if type1.same_as(specialized_type):
  2765. if op == 'in':
  2766. return true_node
  2767. else:
  2768. return false_node
  2769. if op == 'not_in':
  2770. return true_node
  2771. return false_node
  2772. return node
  2773. def specialize_type(self, type, pos):
  2774. try:
  2775. return type.specialize(self.local_scope.fused_to_specific)
  2776. except KeyError:
  2777. error(pos, "Type is not specific")
  2778. return type
  2779. def visit_Node(self, node):
  2780. self.visitchildren(node)
  2781. return node
  2782. class DebugTransform(CythonTransform):
  2783. """
  2784. Write debug information for this Cython module.
  2785. """
  2786. def __init__(self, context, options, result):
  2787. super(DebugTransform, self).__init__(context)
  2788. self.visited = set()
  2789. # our treebuilder and debug output writer
  2790. # (see Cython.Debugger.debug_output.CythonDebugWriter)
  2791. self.tb = self.context.gdb_debug_outputwriter
  2792. #self.c_output_file = options.output_file
  2793. self.c_output_file = result.c_file
  2794. # Closure support, basically treat nested functions as if the AST were
  2795. # never nested
  2796. self.nested_funcdefs = []
  2797. # tells visit_NameNode whether it should register step-into functions
  2798. self.register_stepinto = False
  2799. def visit_ModuleNode(self, node):
  2800. self.tb.module_name = node.full_module_name
  2801. attrs = dict(
  2802. module_name=node.full_module_name,
  2803. filename=node.pos[0].filename,
  2804. c_filename=self.c_output_file)
  2805. self.tb.start('Module', attrs)
  2806. # serialize functions
  2807. self.tb.start('Functions')
  2808. # First, serialize functions normally...
  2809. self.visitchildren(node)
  2810. # ... then, serialize nested functions
  2811. for nested_funcdef in self.nested_funcdefs:
  2812. self.visit_FuncDefNode(nested_funcdef)
  2813. self.register_stepinto = True
  2814. self.serialize_modulenode_as_function(node)
  2815. self.register_stepinto = False
  2816. self.tb.end('Functions')
  2817. # 2.3 compatibility. Serialize global variables
  2818. self.tb.start('Globals')
  2819. entries = {}
  2820. for k, v in node.scope.entries.items():
  2821. if (v.qualified_name not in self.visited and not
  2822. v.name.startswith('__pyx_') and not
  2823. v.type.is_cfunction and not
  2824. v.type.is_extension_type):
  2825. entries[k]= v
  2826. self.serialize_local_variables(entries)
  2827. self.tb.end('Globals')
  2828. # self.tb.end('Module') # end Module after the line number mapping in
  2829. # Cython.Compiler.ModuleNode.ModuleNode._serialize_lineno_map
  2830. return node
  2831. def visit_FuncDefNode(self, node):
  2832. self.visited.add(node.local_scope.qualified_name)
  2833. if getattr(node, 'is_wrapper', False):
  2834. return node
  2835. if self.register_stepinto:
  2836. self.nested_funcdefs.append(node)
  2837. return node
  2838. # node.entry.visibility = 'extern'
  2839. if node.py_func is None:
  2840. pf_cname = ''
  2841. else:
  2842. pf_cname = node.py_func.entry.func_cname
  2843. attrs = dict(
  2844. name=node.entry.name or getattr(node, 'name', '<unknown>'),
  2845. cname=node.entry.func_cname,
  2846. pf_cname=pf_cname,
  2847. qualified_name=node.local_scope.qualified_name,
  2848. lineno=str(node.pos[1]))
  2849. self.tb.start('Function', attrs=attrs)
  2850. self.tb.start('Locals')
  2851. self.serialize_local_variables(node.local_scope.entries)
  2852. self.tb.end('Locals')
  2853. self.tb.start('Arguments')
  2854. for arg in node.local_scope.arg_entries:
  2855. self.tb.start(arg.name)
  2856. self.tb.end(arg.name)
  2857. self.tb.end('Arguments')
  2858. self.tb.start('StepIntoFunctions')
  2859. self.register_stepinto = True
  2860. self.visitchildren(node)
  2861. self.register_stepinto = False
  2862. self.tb.end('StepIntoFunctions')
  2863. self.tb.end('Function')
  2864. return node
  2865. def visit_NameNode(self, node):
  2866. if (self.register_stepinto and
  2867. node.type is not None and
  2868. node.type.is_cfunction and
  2869. getattr(node, 'is_called', False) and
  2870. node.entry.func_cname is not None):
  2871. # don't check node.entry.in_cinclude, as 'cdef extern: ...'
  2872. # declared functions are not 'in_cinclude'.
  2873. # This means we will list called 'cdef' functions as
  2874. # "step into functions", but this is not an issue as they will be
  2875. # recognized as Cython functions anyway.
  2876. attrs = dict(name=node.entry.func_cname)
  2877. self.tb.start('StepIntoFunction', attrs=attrs)
  2878. self.tb.end('StepIntoFunction')
  2879. self.visitchildren(node)
  2880. return node
  2881. def serialize_modulenode_as_function(self, node):
  2882. """
  2883. Serialize the module-level code as a function so the debugger will know
  2884. it's a "relevant frame" and it will know where to set the breakpoint
  2885. for 'break modulename'.
  2886. """
  2887. name = node.full_module_name.rpartition('.')[-1]
  2888. cname_py2 = 'init' + name
  2889. cname_py3 = 'PyInit_' + name
  2890. py2_attrs = dict(
  2891. name=name,
  2892. cname=cname_py2,
  2893. pf_cname='',
  2894. # Ignore the qualified_name, breakpoints should be set using
  2895. # `cy break modulename:lineno` for module-level breakpoints.
  2896. qualified_name='',
  2897. lineno='1',
  2898. is_initmodule_function="True",
  2899. )
  2900. py3_attrs = dict(py2_attrs, cname=cname_py3)
  2901. self._serialize_modulenode_as_function(node, py2_attrs)
  2902. self._serialize_modulenode_as_function(node, py3_attrs)
  2903. def _serialize_modulenode_as_function(self, node, attrs):
  2904. self.tb.start('Function', attrs=attrs)
  2905. self.tb.start('Locals')
  2906. self.serialize_local_variables(node.scope.entries)
  2907. self.tb.end('Locals')
  2908. self.tb.start('Arguments')
  2909. self.tb.end('Arguments')
  2910. self.tb.start('StepIntoFunctions')
  2911. self.register_stepinto = True
  2912. self.visitchildren(node)
  2913. self.register_stepinto = False
  2914. self.tb.end('StepIntoFunctions')
  2915. self.tb.end('Function')
  2916. def serialize_local_variables(self, entries):
  2917. for entry in entries.values():
  2918. if not entry.cname:
  2919. # not a local variable
  2920. continue
  2921. if entry.type.is_pyobject:
  2922. vartype = 'PythonObject'
  2923. else:
  2924. vartype = 'CObject'
  2925. if entry.from_closure:
  2926. # We're dealing with a closure where a variable from an outer
  2927. # scope is accessed, get it from the scope object.
  2928. cname = '%s->%s' % (Naming.cur_scope_cname,
  2929. entry.outer_entry.cname)
  2930. qname = '%s.%s.%s' % (entry.scope.outer_scope.qualified_name,
  2931. entry.scope.name,
  2932. entry.name)
  2933. elif entry.in_closure:
  2934. cname = '%s->%s' % (Naming.cur_scope_cname,
  2935. entry.cname)
  2936. qname = entry.qualified_name
  2937. else:
  2938. cname = entry.cname
  2939. qname = entry.qualified_name
  2940. if not entry.pos:
  2941. # this happens for variables that are not in the user's code,
  2942. # e.g. for the global __builtins__, __doc__, etc. We can just
  2943. # set the lineno to 0 for those.
  2944. lineno = '0'
  2945. else:
  2946. lineno = str(entry.pos[1])
  2947. attrs = dict(
  2948. name=entry.name,
  2949. cname=cname,
  2950. qualified_name=qname,
  2951. type=vartype,
  2952. lineno=lineno)
  2953. self.tb.start('LocalVar', attrs)
  2954. self.tb.end('LocalVar')