NL i&dZddlmZddlmZddlmZmZmZm Z m Z m Z m Z ddl mZmZmZddlmZmZmZmZmZddlmZmZmZmZmZmZddlmZdd l m!Z!m"Z"m#Z#dd l$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*dd l+m,Z,d5d Z- d6d Z.d7dZ/d8dZ0d9dZ1d:dZ2 d;dZ3d5dZ4 d;dZ5ddZ;d?dZ< d@dZ=ddd d!d"d#d$Z>dAd%Z?dGsZ((K@N<D&) $RWW  @N r1c tDcic]#}||Dcgc]}|j|k(s|c}%c}}Scc}wcc}}w)zGroup arguments by kind.)r kind)argskargs r/make_arg_groupsrDYs3?F G!At5sxx1}5 5 GG5 Gs ;66;;cP|t|tz|tz|tzS)z@Reorder argument groups to match their order in a format string.)rrrr)groupss r/reorder_arg_groupsrG^s) '?VG_ ,vm/D DviGX XXr1c>djd|D}d|dS)Nc3<K|]}d|jdyw)"z", Nr(.0rCs r/ z%make_static_kwlist..ds:c!CHH:S):sz&static const char * const kwlist[] = {z0};)join)rA arg_namess r/make_static_kwlistrRcs%:T::I 4YKt DDr1cd}|ts |tr|dz }|dt|tzz }|ts|t s |t r|ddt|tzzz }|t s |t r|ddt|t zzz }|t r|ddt|t zzz }||d|z }|S)a Return a format string that specifies the accepted arguments. The format string is an extended subset of what is supported by PyArg_ParseTupleAndKeywords(). Only the type 'O' is used, and we also support some extensions: - Required keyword-only arguments are introduced after '@' - If the function receives *args or **kwargs, we add a '%' prefix Each group requires the previous groups' delimiters to be present first. These are used by both vectorcall and legacy wrapper functions. rI%O|$@:)r r lenrrrr) func_namerFr*s r/make_format_stringr\hsF h6),#  cCw(((F g&/6)3D#c&/2222 my 1#c&"78888 i#c&"34444Ai[/! Mr1c |jt||jdt|j}|j j r|d|j j }|jrM|jjtk7r0|jd}|jd|jdt|}t|}|jt|t!|j|}|jd|d|D];}|jdj#|j|j$rd nd =|t&|t(zDcgc]}d |jd } }g} |t&s |t(rP| |t&rd |t&djndgz } | |t(rd |t(djndgz } | |Dcgc]}d |jc}z } |jdk(rd} nd} d} |sd} nYt+|dk(rt+|t,dk(rd} n3t+|t+|t,t+|t.zk(rd} |j1dj#| | d j3d| Dddt5|j j D](} t7| }|jt8d|d*t;||||}t=|||t.|t>z| ||jdycc}wcc}w)zGenerate a CPython-compatible vectorcall wrapper for a native function. In particular, this handles unboxing the arguments, calling the native function, and then boxing the return value.  {NrPyObject *obj_ = self;z static CPyArg_Parser parser = {"z", kwlist, 0};PyObject *obj_{}{}; = NULLrICPy_DECREF(obj_);&obj_NULL__call__zPyVectorcall_NARGS(nargs)nargsCPyArg_ParseStackAndKeywords"CPyArg_ParseStackAndKeywordsNoArgs"CPyArg_ParseStackAndKeywordsOneArg"CPyArg_ParseStackAndKeywordsSimplez)if (!{}(args, {}, kwnames, &parser{})) {{c3&K|] }d|z yw, NrNns r/rOz,generate_wrapper_function..s$@!TAX$@ return NULL;}  = 0;cleanupsr=) emit_liner0r.listrAsignum_bitmap_args class_namedeclr@rpopr(rDrGrRr\r*optionalr r rZrr emit_linesrPrangerrr>generate_wrapper_corer)r-r9r:r; real_argsrCrFreordered_argsfmtrzarg_ptrsrhparse_fnir(r=s r/generate_wrapper_functionrs* 0W]]CDCHIRWW I vv7!7!7 78  }})::mmAN388*H=> Y 'F'/N (89 RWWf -C 9#oNO  ! ( ( 9RT U  ;A:JVT]M^:^_3/#((2._H_H h6),6(;KuVH-a05567QWXXF95 #>>H ww*+-H 7 Y1 VG_!5!:7 Y3vg/#fWo2FF F7 3:: eRWW$@x$@@   266)) *81~[M4&678-R+{SN w&//%  cU` ?s 7M 9McNdjt|j|S)NzFPyObject *{prefix}{name}(PyObject *self, PyObject *args, PyObject *kw)r&)r*rr+r,s r/legacy_wrapper_function_headerrs( S Z ZBHHUO [ r1c |jt||jdt|j}|j j r|d|j j }|jrf|jjdk(s|jjtk7r0|jd}|jd|jdt|}t|}|jt||D];}|jdj!|j|j"rdnd =|t$|t&zDcgc]}d |jd }}g} |t$s |t&rP| |t$rd |t$djnd gz } | |t&rd |t&djnd gz } | |Dcgc]}d |jc}z } |j)dj!t+d||jd j-d| Dddt/|j j D](} t1| } |jt2d| d*t5||||} t7|||t8|t:z|| |jdycc}wcc}w)zGenerates a CPython-compatible legacy wrapper for a native function. In particular, this handles unboxing the arguments, calling the native function, and then boxing the return value. r^N__new__rr_r`rarbrIrcrdrerfzEif (!CPyArg_ParseTupleAndKeywords(args, kw, "{}", "{}", kwlist{})) {{c3&K|] }d|z ywrorqrrs r/rOz3generate_legacy_wrapper_function.. s>ZAtax>Zrtrurvrwrxry)r{rr.r|rAr}r~rrr(r@rrrDrGrRr*rr r rr\rPrrrr>rrr) r-r9r:r;rrCrFrrzrrr(r=s r/ generate_legacy_wrapper_functionrs 7GMMJK3OPRWW I vv7!7!7 78  }}"'',,)3rww||GX7XmmAN388*H=> Y 'F'/N (89  ! ( ( 9RT U  ;A:JVT]M^:^_3/#((2._H_H h6),6(;KuVH-a05567QWXXF95 #>>H OVV tV ,bggrww>ZQY>Z7Z   266)) *81~[M4&678-R+{SN w&//%  c7` ?s %K'K ct||}|j||j|j|j |j |j S)zGenerates a wrapper for native __dunder__ methods to be able to fit into the mapping protocol slot. This specifically means that the arguments are taken as *PyObjects and returned as *PyObjects. )WrapperGenerator set_target emit_headeremit_arg_processing emit_callfinish wrapper_nameclr-r9gens r/generate_dunder_wrapperr"sS 2w 'CNN2OOMMOJJL    r1cLt||}|j|t|jdvsJdgd|_|j |j t|||ddg|j|j|jS)zGenerate a wrapper for native __ipow__. Since __ipow__ fills a ternary slot, but almost no one defines __ipow__ to take three arguments, the wrapper needs to tweaked to force it to accept three arguments. )z*__ipow__ should only take 2 or 3 arguments)selfexpmodz[PyErr_SetString(PyExc_TypeError, "__ipow__ takes 2 positional arguments but 3 were given");ruif_unsupported) rrrZrArQrrhandle_third_pow_argumentrrrrs r/generate_ipow_wrapperr0s 2w 'CNN2 rww<6 !O#OO !*CMOO  i  MMOJJL    r1ct||}|j||jdvr gd|_n ddg|_|j }|j |jt vr!|jtvrt||||St |j}|j|}|t||||St||||||S)aGenerates a wrapper for a native binary dunder method. The same wrapper that handles the forward method (e.g. __add__) also handles the corresponding reverse method (e.g. __radd__), if defined. Both arguments and the return value are PyObject *. __pow____rpow__)leftrightrrr) rrr(rQrrrr $generate_bin_op_reverse_only_wrapper get_method$generate_bin_op_forward_only_wrappergenerate_bin_op_both_wrappers)rr-r9rrrmethodfn_revs r/generate_bin_op_wrapperrJs 2w 'CNN2 ww))0 ) ##%LOO ww((RWW8O-O,R#> %RWW-w' > 0Wc B  *"b&'3 G r1rc|jtddt|||dg|jd|j |j dt ||t|j|jy)NtypefailFerrorraise_exceptiongoto typefail;rnot_implemented_handler) rrrremit_error_handling emit_label#generate_bin_op_reverse_dunder_callrr(rr-r9rs r/rrjsx+j"95Qb'3@P?QRMM*:M; z" (G5G5PQJJLr1c4ddg|_|jtddt|||dg|j |j |j d|jd|jd |jy) NrrrFrrrPy_INCREF(Py_NotImplemented);return Py_NotImplemented;) rQrrrrrrr{rrs r/rrsf%CM+j"95Qb'3@P?QRMMO z" 56 12JJLr1c|jdj|j||jt ddt |||dg|j dk(rt|jdk(rd}nd }|j| |j|jd |jd|jd j|j||j|d dg|_ |jt ddt |||dg|j|j|jdt|||j |jd |jd|jd|jd|jy)Nz5if (PyObject_IsInstance(obj_left, (PyObject *){})) {{rFrzgoto typefail2;rrrrrrvz6if (PyObject_IsInstance(obj_right, (PyObject *){})) {{rr typefail2} else {rr)r{r*type_struct_namerrrr(rZrArrrrrQrr)rr-rr9rfwd_not_implemented_handlers r/rrs ?FF  $ $R (  +j"95Qb'3@Q?RS ww)BGG  1&7#&6#MM*EMF c z" @GG  $ $R (  NN6f%CM+k":ERfgsDUCVWMMO j!'GV[[A c {# 56 12JJLr1cv|jdvr|jd|jd|d|jdjt|j||jdvrE|jd|jd|jd|jd yy) Nrzif (obj_mod == Py_None) {z_Py_IDENTIFIER(rdzDreturn CPy_CallReverseOpMethod(obj_left, obj_right, "{}", &PyId_{});rrrrv)r(r{r*r )r-r9rs r/rrs ww))56 y34 NUU !"'' *G   ww))*%9:56# *r1ch|jdvry|jdvrt|jdk(s|jdk(rn|jd|D]}|j||jdt|jdk(r|jj yyy)N)rr__ipow__)rrrrzif (obj_mod != Py_None) {rvr)r(rZrAr{rQr)r-r9rrr8s r/rrs ww99 **s277|q/@RWWPZEZ 56" $D   d # $# s}}  " MM    #F[r1Py_LTPy_GTPy_LEPy_GEPy_EQPy_NE)__lt____gt____le____ge____eq____ne__c$tfdtD}|sytdj|j}|j dj ||j d|D]T}|j dt|dj|}|Jt||d d g |j d V|j d |j d |j d|j d |S)z3Generates a wrapper for richcompare dunder methods.c3FK|]}j|s|ywN) has_method)rNr(rs r/rOz/generate_richcompare_wrapper..sMdt9LTMs!!N _RichCompare_zHstatic PyObject *{name}(PyObject *obj_lhs, PyObject *obj_rhs, int op) {{rLz switch (op) {zcase z: {lhsrhs)rQrvrr) sortedRICHCOMPARE_OPSr name_prefixr.r{r*rr)rr9matchesr(funcmethods` r/generate_richcompare_wrapperrsMoMMG _M"..*G)H ID RYY Z   o&E/$"7!8=>t$!!!fg%H#   c 56 12 c Kr1cRt|j|j|j}|j dj ||j d|j dt |j|jd|j d|S)z/Generates a wrapper for native __get__ methods.zOstatic PyObject *{name}(PyObject *self, PyObject *instance, PyObject *owner) {{rLz)instance = instance ? instance : Py_None;return z(self, instance, owner);rv)rr(rr.r{r*rr+rr-r9r(s r/generate_get_wrapperrs_RWWIbnnW]]&C%D ED Y`` a   AB  rxx /F.GG_`a c Kr1c t|j|j|j}|j d|d|j dj |j |j|j|jt|j|j|jd|jdt|jr|j dn|j d|jd|j|j d|j d |j d |j d |S) z0Generates a wrapper for native __hash__ methods.static Py_ssize_t (PyObject *self) {{}retval = {}{}{}(self);retval return -1;-Py_ssize_t val = CPyTagged_AsSsize_t(retval);*Py_ssize_t val = PyLong_AsSsize_t(retval); if (PyErr_Occurred()) return -1;zif (val == -1) return -2; return val;rvrr(rr.r{r* ctype_spacedret_typeget_group_prefixrrr+emit_error_checkr! emit_dec_refrs r/generate_hash_wrapperr#s'_RWWIbnnW]]&C%D ED *4&0CDE "))   -  $ $RWW -  HHW]] #   Xr{{LA%IJFG 2;;/ 89 12 m$ c Kr1c t|j|j|j}|j d|d|j dj |j |j|j|jt|j|j|jd|jdt|jr|j dn|j d|jd|j|j d|j d |j d |S) z/Generates a wrapper for native __len__ methods.rrrrrrrrrrvrrs r/generate_len_wrapperr>s_RWWIbnnW]]&C%D ED *4&0CDE "))   -  $ $RWW -  HHW]] #   Xr{{LA%IJFG 2;;/ 89 m$ c Kr1c t|j|j|j}|j d|d|j dj |j |jt|j|j|jd|jdt|jsJd|j d|j d|S) z0Generates a wrapper for native __bool__ methods. static int rz{}val = {}{}(self);valrz'Only bool return supported for __bool__rrv) rr(rr.r{r*rrrr+rr rs r/generate_bool_wrapperrWs_RWWIbnnW]]&C%D ED  D6)<=> $$   -}bhhw}}>U   UBKK> bkk *U,UU * m$ c Kr1cdjtd|j|j}dj d|j D}|j d|d|dt|||j |S)zzGenerates a wrapper for native __delitem__. This is only called from a combined __delitem__/__setitem__ wrapper. {}{}{} __delitem__rpc3:K|]}d|jywr_NrLrMs r/rOz,generate_del_item_wrapper..qsJ3^CHH:6Jr() {)r*rrr.rPrAr{#generate_set_del_item_wrapper_inner)rr-r9r( input_argss r/generate_del_item_wrapperr ksm ??=- 9V WDJ"''JJJ  D6:,d;<'GRWW= Kr1c |jd}d}|r|d|k(rt||d|}|j}|jdk(r"t |t dt tgz}djtd|j|j}djd |D}|jd |d |d |jd |djd|6|jd|d|djd|djdn|jd|djd|jd|jdj|dj|jd|jd|jd|jd|jd}|r|d|k(rt||||S|jd|djd|jd|jd|C|j7d|jd}|jd|d|jd n;|jd!j|dj|dj|jd|jd|jd|jd|S)"aGenerates a wrapper for native __setitem__ method (also works for __delitem__). This is used with the mapping protocol slot. Arguments are taken as *PyObjects and we return a negative C int on error. Create a separate wrapper function for __delitem__ as needed and have the __setitem__ wrapper call it if the value is NULL. Return the name of the outer (__setitem__) wrapper. rNrkr___valuer __setitem__rpc3:K|]}d|jywrrLrMs r/rOz0generate_set_del_item_wrapper..sG3^CHH:6Grrrr if (obj_r == NULL) {rz(obj_z, obj_rdz4PyObject *super = CPy_Super(CPyModule_builtins, obj_zif (super == NULL) return -1;zJPyObject *result = PyObject_CallMethod(super, "__delitem__", "O", obj_{});zPy_DECREF(super);zPy_XDECREF(result);zreturn result == NULL ? -1 : 0;rvzPyObject *result;'z)' object does not support item assignmentz"PyErr_SetString(PyExc_TypeError, "z");zresult = NULL;zIresult = PyObject_CallMethod(super, "__setitem__", "OO", obj_{}, obj_{});)get_method_and_classr rAr(r|rr#rr*rrr.rPr{r  builtin_base) rr-r9 method_clsdel_namerAr(r msgs r/generate_set_del_item_wrapperrws((7JHjmr),RAH 77D ww-DzZ 4EwOPP ??=- 9V WDG$GGJ  D6:,d;< al;<GH:U47<<.tAw||nTVWX PQUVWQXQ]Q]P^^`ab9: X _ _Q   -./0;< c((7Jjmr)+B>* K' PQUVWQXQ]Q]P^^`ab9:-.  "//"9bggYGHC    B3%sK L   . /   [bbGLL$q',,  -./0;<# Kr1c D|D]-}t|j|j|td/dj d|D}|j dj |j|jt|j|j||jd|jd|jd|j|j d|jd|j d|j d y) Nfailrpc3:K|]}d|jywarg_NrLrMs r/rOz6generate_set_del_item_wrapper_inner..s>#d388*->rz{}val = {}{}({});rz goto fail;z return 0;rrv)generate_arg_checkr(typerrPr{r*rrrr+r.rrr)r-r9rArC native_argss r/r r sM388SXXw F8KLM))>>>K ""   -}bhhw}}>UWb   UBKK>  , k" v l# cr1c t|j|j|j}|j d|dt d|j dj|td|j dj|j|jt|j|j|jd|jdt|jr|j d n>|j d |j!d|j|j d |j d |S) z5Generates a wrapper for a native __contains__ method.rz&(PyObject *self, PyObject *obj_item) {itemrkz-1z{}val = {}{}(self, arg_item);rrrz#int boolval = PyObject_IsTrue(val);zreturn boolval;rv)rr(rr.r{rrAr rr*rrrr+rr rrs r/generate_contains_wrapperr$s_RWWIbnnW]]&C%D ED  D6)PQRvrwwqzt9LM '..   -}bhhw}}>U   UBKK>"++&-(?@UBKK0+, c Kr1NcBtd|}|j||r||_|xsg|_|xsg|_|xsd|_|j s tdn td}|j||j|jy)a?Generates the core part of a wrapper function for a native function. This expects each argument as a PyObject * named obj_{arg} as a precondition. It converts the PyObject *s to the necessary types, checking and unboxing if necessary, makes the call, then boxes the result if necessary and returns it. NrIrfr)r) rrrQrz optional_argsr=use_gotorrrrr)r-r9r&rQrzr=rrs r/rrs 4 )CNN2! >rCL%+C'-2C),M& ![=PE%(MMOr1FT)rrbitmap_arg_indexc X|xs t}|jr|jr|r|j|}|j |j |d|d|d|j d|dt |tz}|j |d|tdz zd|jd|d ||d ||d |j d y|jd|d ||d ||d |yt|r|rl|j d|d|j d|d|j d |d|j|d|jdd |d|dd y|j d|d|dy|jd|d ||d |||y)zInsert a runtime check for argument and unbox if necessary. The object is named PyObject *obj_{}. This is expected to generate a value of name arg_{} (unboxed if necessary). For each primitive a runtime check ensures the correct type. z arg_z = ;rz != NULL) {z |= 1 << rkobj_rFT) declare_destrrborrowrv)r,rrr-rzPyObject *arg_rrz = obj_z; )r,rrrN) r is_unboxed error_overlapc_undefined_valuer{ctyperr emit_unboxr" c_error_valuer emit_cast) r(typr9rrrr(initbitmaps r/rrs  $]_E ~~   ,,S1D   s!3 4E$s4&J K   l; < !1[!@AF    2BkTUo2V1WWXY Z   tf tf " /     c "   tf tf ! /!   c "    tfA6 7   l; <   TF#g.C.CC.H-IK L   zT$wtfB+G M   tfGD6C D4&M4&M +  r1cpeZdZdZd dZddZddZddZddZ d ddZ ddd Z dd Z dd Z dd Z y)rz;Helper that simplifies the generation of wrapper functions.cJ||_||_g|_g|_d|_y)NrI)rr9rzr&r=)rrr9s r/__init__zWrapperGenerator.__init__Ns' #% /1 r1c|j|_|j|jj|_|j j|_|jr |jd|j |_n|j|_|jDcgc]}|jc}|_ |j|_ ycc}w)zSet the wrapped function. It's fine to modify the attributes initialized here later to customize the wrapper function. N) r( target_namer+r9r. target_cnamer}r~rArQr)rr-rCs r/rzWrapperGenerator.set_targetUs 77HHT\\%7%78!vv55    74#7#7"78DIDI.2ii8s#((8  9s"Ccdjt|j|jr3|jj |j j SdS)z(Return the name of the wrapper function.rrI)r*rr<rrr9r.rs r/rzWrapperGenerator.wrapper_nameesR    7;wwDGG   2 2 3  EG  r1cHt|jxs |jS)zADo we use a goto for error handling (instead of straight return)?)boolrzr=r?s r/r'zWrapperGenerator.use_gotomsDMM8T%8%899r1cdjd|jD}|jjdj |j |y)z7Emit the function header of the wrapper implementation.rpc3&K|] }d| ywrrqrMs r/rOz/WrapperGenerator.emit_header..ssP#u5Prtz(static PyObject *{name}({input_args}) {{)r(r N)rPrQr9r{r*r)rr s r/rzWrapperGenerator.emit_headerqsMYYPPP   6 = =&&(Z >  r1Nc R|xs|j}d}t|j|jD]n\}}|jt t fvr |jnt}||jv}t|||j|||||s]|jsj|dz }py)z*Emit validation and unboxing of arguments.r)rrr(rkN) rziprQrAr@r r r r#r&rr9r/)rrrr(arg_namerCr5rs r/rz$WrapperGenerator.emit_arg_processingzs% ; &MHc!hhx.CC#((IZCd000H   /!!1 C-- A%  &r1cdjd|jD}|jrKdjtt |jDcgc] }t |c}}|d|}|j }|j}|js|jr|jdj|j|t|j||j|j |jr(|j#d|d|j%dd|d|jd j|jr dydy|rUt'|t(sE|jd jt|j||jd |d d y|jdt|jd|dycc}w)zEmit call to the wrapper function. If not_implemented_handler is non-empty, use this C code to handle a NotImplemented return value (if it's possible based on the return type). rpc3&K|] }d| ywrrqrMs r/rOz-WrapperGenerator.emit_call..sG$se Grtz{}retval = {}{}({});rruretboxT)r,z return {};zPyObject *retbox = {}{}({});z"if (retbox == Py_NotImplemented) {rvzreturn retbox;rrrdN)rPrQr~reversedrrrr9r.r'r{r*rrr=rrzremit_box isinstancer)rrr!r bitmap_argsrr9s r/rzWrapperGenerator.emit_calls iiGGG   )))1%8L8L2M)NOAQOK)MK=9K==,,   $--/   &--((2M4CTCTVa  G   .""((8^L  8XD Q   l11h>Q>Q(` aW_` a&z(I/N!!299%t'8'8+ ""8+$ !!GM?4;L;L:MQ{m[]"^_GPsG3c^|js |jr tdStdS)z2Figure out how to deal with errors in the wrapper.rrf)rzr=rrr?s r/rzWrapperGenerator.errors) ==D//v& &!( (r1c|j}|jrc|jd|j|j|j r|j |j |j dyy)z?Emit error handling block at the end of the wrapper, if needed.rruN)r9r'rrrzr=r{)rr9s r/rz$WrapperGenerator.emit_error_handlingsf,, ==?   v & G   .""!!$"5"56   n - r1c:|jjdy)Nrv)r9r{r?s r/rzWrapperGenerator.finishs s#r1)rzClassIR | Noner9rreturnNone)r-rrQrR)rQstr)rQrA)rQrR)NT)rErrorHandler | NonerrArQrR)rI)rrSrQrR)rQr)__name__ __module__ __qualname____doc__r:rrr'rrrrrrrqr1r/rrIsXE!$  : JN&(&BF& &,,`^).$r1)r-rr.r$rQrS) r-rr9rr:rSr;rSrQrS)rAlist[RuntimeArg]rQdict[ArgKind, list[RuntimeArg]])rFrZrQrY)rArYrQrS)r[ str | NonerFrZrQrS) r-rr9rr:rSr;rSrQrR)rrr-rr9rrQrS)r-rr9rrrrQrR) rrr-rrrr9rrrrQrR)r-rr9rrrSrQrR) r-rr9rrrrz list[str]rQrR)rrr9rrQr[)r-rr9rrAzSequence[RuntimeArg]rQrR)NNNN)r-rr9rr&zlist[RuntimeArg] | NonerQlist[str] | Nonerzr\r=r[rQrRr)r(rSr5rr9rrrTrrArrAr(intrQrR)KrX __future__rcollections.abcr mypy.nodesrrrrr r r mypy.operatorsr r rmypyc.codegen.emitrrrrr mypyc.commonrrrrrrmypyc.ir.class_irrmypyc.ir.func_irrrrmypyc.ir.rtypesrrr r!r"r# mypyc.namegenr$r0r>rDrGrRr\rrrrrrrrrrrrrrrrrr rr r$rrrrqr1r/rhs #$___]]__&BB(* 2 /2AD$H Y E