ParseTreeTransforms.py 136 KB

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