o
    @aE                     @   s  d Z ddlmZmZ ddlmZ ddlmZmZm	Z	m
Z
 ddlmZmZmZmZ ddlmZ ddlmZmZ ddlmZmZ dd	lmZ dd
lmZ ddlmZ ddlmZ ddlmZ ddl m!Z!m"Z" ddl m#Z# ddl$m%Z%m&Z&m'Z' ddl(m)Z) ddl*m+Z+ ddl,m-Z- ddl.m.Z. ddl/m0Z0 ddl1m2Z2 ddl3m4Z4 ddl5m6Z6m7Z7 ddl8Z9ddl:Z:ddl;Z<ddl=Z=ddl>Z>ddl?Z?ddl@mAZA ddlBZBe:CdZDdd ZEdd ZFdd  ZGd!d" ZH		d4d#d$ZId5d%d&ZJ		d4d'd(ZKd6d)d*ZLd7d,d-ZM		+	d8d.d/ZN		+d9d0d1ZOd2d3 ZPdS ):z
This module contains all the stuff to make your way from python code to
a dynamic library, see __init__.py for exported interfaces.
    )CxxPython)cfg)PythonModuleIncludeLine	Statement)FunctionBodyFunctionDeclarationValueBlock)ReturnStatement)PythranExtensionPythranBuildExt)refinemark_unexported_functions)PassManager)pythran_ward)tog)pytype_to_depspytype_to_ctype)load_specfileSpec)spec_to_string)check_specscheck_exportsPythranSyntaxError)__version__)cxxidN)datetime)CompileError)	sysconfig)setup)mkdtempNamedTemporaryFile)reducepythranc                 C   sp   t  }| j D ]}|D ]}|D ]	}|t| qqq| j D ]}|D ]	}|t| q%q!t|dd dS )zD Extract types dependencies from specs for each exported signature. c                 S   s   d| vS )NZinclude )xr(   r(   3/usr/lib/python3/dist-packages/pythran/toolchain.py<lambda>;   s    z-_extract_specs_dependencies.<locals>.<lambda>)key)set	functionsvaluesupdater   capsulessorted)specsZdeps
signatures	signaturetr(   r(   r*   _extract_specs_dependencies+   s   r7   c                 C   s>   |  d}t|dkrddg| }tt|dd t|d S )zqTurns an optimization of the form
        my_optim
        my_package.my_optim
        into the associated symbol.   r'   optimizationsNr   )splitlenr&   getattr
__import__)optimizationZsplittedr(   r(   r*   _parse_optimization>   s   
r@   c                 C   sB   t d|dd}||  |jW  d   S 1 sw   Y  dS )zwrite `content` to a temporary XXX`suffix` file and return the filename.
       It is user's responsibility to delete when done.wF)modesuffixdeleteN)r%   writename)contentrC   outr(   r(   r*   _write_tempI   s   
$rI   c                 C   s<   | j D ]}t|tjr|j|krdd |jjD   S qg S )z(Checks if a given function has argumentsc                 S   s   g | ]}t |jqS r(   )r   id).0argr(   r(   r*   
<listcomp>U   s    z has_argument.<locals>.<listcomp>)body
isinstanceastZFunctionDefrF   args)modulefnamenr(   r(   r*   has_argumentQ   s
   
rU   c                 C   sh   t | |}t||\}}|durt||}|du r"tdd }dd |D }t||| |||fS )z*Front-end and middle-end compilation stepsNr'   r:   c                 S      g | ]}t |qS r(   )r@   )rK   Zoptr(   r(   r*   rM   h       z$front_middle_end.<locals>.<listcomp>)r   frontendparser   r   getr;   r   )module_namecoder:   
module_direntry_pointspmir
docstringsr(   r(   r*   front_middle_endY   s   


rb   c                 C   s    t | |||\}}}|t|S )zYpython + pythran spec -> py code

    Prints and returns the optimized python code.

    )rb   dumpr   )r[   r\   r:   r]   r_   r`   _r(   r(   r*   generate_pyq   s   re   c                    s2  r	t  }nd}t| ||||d\} }|t }du r7G dd dt}	|	|}
 fdd}|
|fS ttrAti  fdd}	| t
|  t|tr[|}n|dd	}t| tt d
}t| ||}
|
tdtdtdtdtd |
jdd tD   |
j|j  |
td dd }j D ]~\}}t|}|s|
|d|| | t|D ]c\}}d||}dd |D }t |}dd t ||D }t!d }d"|}|| ||rd|nd}d| }|
#t$t%t&||dd t ||D t't(d|| |d"|g||| qqj) D ]g\}}t|}d d |D }t |}d!d t ||D }t!d }d"|}|| ||r`d|nd}d| }t*||}|
+t$t%t&||d"d t ||D t't,d#|| |d"|g|| q-|
|fS )$zpython + pythran spec -> c++ code
    returns a PythonModule object and an error checker

    the error checker can be used to print more detailed info on the origin of
    a compile error (e.g. due to bad typing)

    N)r^   c                   @   s    e Zd Zdd Zdd ZeZdS )zgenerate_cxx.<locals>.Generablec                 S   s
   || _ d S N)rG   )selfrG   r(   r(   r*   __init__      
z(generate_cxx.<locals>.Generable.__init__c                 S   s
   t | jS rf   )strrG   )rg   r(   r(   r*   __str__   ri   z'generate_cxx.<locals>.Generable.__str__N)__name__
__module____qualname__rh   rk   Zgenerater(   r(   r(   r*   	Generable   s    ro   c                      s   t   d S rf   )r   	typecheckr(   )r`   r(   r*   error_checker   s   z#generate_cxx.<locals>.error_checkerc                     s   t  } t|  d S rf   )r   rp   r   )typesr`   r3   r(   r*   rq      s   
asciiignore)hashversiondatezpythonic/core.hppzpythonic/python/core.hppzpythonic/types/bool.hppzpythonic/types/int.hppz&#ifdef _OPENMP
#include <omp.h>
#endifc                 S   rV   r(   )r   )rK   Zincr(   r(   r*   rM      rW   z generate_cxx.<locals>.<listcomp>z%pythonic/python/exception_handler.hppc                 S   s   t d| | S )Nz{0}::{1})r   format)r[   Zinternal_namer(   r(   r*   warded   s   zgenerate_cxx.<locals>.wardedz{}()()z{0}{1}c                 S   rV   r(   r   rK   r6   r(   r(   r*   rM      rW   c                 S      g | ]\}}|qS r(   r(   rK   rT   rd   r(   r(   r*   rM      rW   z{0}::{1}::type{2}z, z<{0}> ztypename %s::result_typec                 S   s   g | ]\}}t |d  |qS )z&&r   rK   r6   ar(   r(   r*   rM      s    a  
                            PyThreadState *_save = PyEval_SaveThread();
                            try {{
                                auto res = {0}()({1});
                                PyEval_RestoreThread(_save);
                                return res;
                            }}
                            catch(...) {{
                                PyEval_RestoreThread(_save);
                                throw;
                            }}
                            c                 S   rV   r(   r   r{   r(   r(   r*   rM      rW   c                 S   r|   r(   r(   r}   r(   r(   r*   rM     rW   c                 S   s   g | ]	\}}t ||qS r(   r   r   r(   r(   r*   rM     s    z
{0}()({1}))-r-   keysrb   rc   r   objectrO   dictr   Zto_docstringsr   bytesencodehashlibZsha256Z	hexdigestr   r    Znowr   Zadd_to_includesr   r   r7   rN   r.   itemsr   Zadd_global_varry   	enumeraterU   zipr   joinZadd_pyfunctionr	   r
   r   r   r   r1   r   Zadd_capsuler   )r[   r\   r3   r:   r]   r^   r_   ra   rG   ro   modrq   Z
code_bytesZmetainforz   Zfunction_namer4   Zinternal_func_nameZsigidr5   Znumbered_function_nameZarguments_typesZarguments_namesZ	argumentsZname_fmtZ	args_listZspecialized_fnameZresult_typeZ	docstringr(   rs   r*   generate_cxx|   s   		z






*


	r   c                 K   sb  t  }t  }t| |gfi |}zt| |gdtidttjr!dnddd|d|gd W n ty> } zt	t
|d}~ww d	d
 }td}	ttj|| d D ]B}
|
|	ru|rd|d|	}ntjt | |	 }||
| qT|r|dd}tj|}nt }||
tj|tj|
 qTt| t| td|   td|  |S )zyc++ file -> native module
    Return the filename of the produced shared library
    Raises CompileError on failure

    Z	build_extzsetup.pyz	--verbosez--quietz--build-libz--build-temp)rF   Zext_modulesZcmdclassscript_nameZscript_argsNc              	   S   sx   t | d-}t |d}||  W d    n1 sw   Y  W d    d S W d    d S 1 s5w   Y  d S )Nrbwb)openrE   read)Zsrc_fileZ	dest_filesrcdestr(   r(   r*   copy:  s   "zcompile_cxxfile.<locals>.copyZ
EXT_SUFFIX*%{ext}r~   zGenerated module: zOutput: )r$   r   r#   r   loggerZisEnabledForloggingINFO
SystemExitr!   rj   r"   Zget_config_varglobospathr   endswithreplacegetcwddirnamebasenameshutilrmtreeinfo)r[   Zcxxfileoutput_binarykwargsZbuilddirZbuildtmp	extensioner   extfZoutput_directoryr(   r(   r*   compile_cxxfile  sT   





r   Fc                 K   sB   t |d}t| ||fi |}|st| |S td|  |S )zZc++ code (string) -> temporary file -> native module.
    Returns the generated .so.

    .cppz!Keeping temporary generated file:)rI   r   r   remover   warning)r[   Zcxxcoder   Z	keep_tempr   Zfdpathr(   r(   r*   compile_cxxcodeY  s   

r   c                 K   sX  |r*t | |||}	|du rt|	 dS t|	d}
|d}t|
| td|  ddlm	} |du r8||}t
| ||||\}}d|dg v ra|jdtd |jdtd	tjj |rtt|d
}
|rs|dd
}n| d
 }t|
| td|  |S zt| t|fd|i|}W |S  ty   td |  td  w )a   Pythran code (string) -> c++ code -> native module

    if `cpponly` is set to true, return the generated C++ filename
    if `pyonly` is set to true, prints the generated Python filename,
       unless `output_file` is set
    otherwise, return the generated native library filename
    Nz.pyzGenerated Python source file: r   )spec_parserZENABLE_PYTHON_MODULEZundef_macrosz#undef ENABLE_PYTHON_MODULEz#define PY_MAJOR_VERSION {}r   r   zGenerated C++ source file: r   z4Compilation error, trying hard to find its origin...z,Nop, I'm going to flood you with C++ errors!)re   printrI   ry   r   mover   r   pythran.specr   r   rZ   Zpreambleinsertr   sysversion_infomajorrj   r   r   r!   r   )r[   Zpythrancoder3   Zoptscpponlypyonlyoutput_filer]   r   rG   Ztmp_filer   rR   rq   r(   r(   r*   compile_pythrancodem  sV   





r   c              
   K   s  |st j| \}}|pt j|d }nt j|dd\}}|p*|ddd }t j| }t j| d d }	t j|	rKt|	}
|d|
 z)t	| }t
|| f||||d|}W d	   W |S 1 smw   Y  W |S  ty } z	|jd	u r| |_ d	}~ww )
a  
    Pythran file -> c++ file -> native module.

    Returns the generated .so (or .cpp if `cpponly` is set to true).

    Usage without an existing spec file

    >>> with open('pythran_test.py', 'w') as fd:
    ...    _ = fd.write('def foo(i): return i ** 2')
    >>> cpp_path = compile_pythranfile('pythran_test.py', cpponly=True)

    Usage with an existing spec file:

    >>> with open('pythran_test.pythran', 'w') as fd:
    ...    _ = fd.write('export foo(int)')
    >>> so_path = compile_pythranfile('pythran_test.py')

    Specify the output file:

    >>> import sysconfig
    >>> ext = sysconfig.get_config_vars()["SO"]
    >>> so_path = compile_pythranfile('pythran_test.py', output_file='foo'+ext)
    r   r   r~   r8   r9   z.pythranr3   )r   r   r   r]   N)r   r   r;   splitextr   r   isfiler   
setdefaultr   r   r   r   filename)Z	file_pathr   r[   r   r   r   rd   r   r]   Z	spec_filer3   fdr   r(   r(   r*   compile_pythranfile  s:   

r   c                  C   s&   d} t d| }|ot| dS  dS )zMSimple passthrough compile test.
    May raises CompileError Exception.

    z*
        #include <pythonic/core.hpp>
    testN)r   r   r   )r\   r   r(   r(   r*   test_compile  s   
r   )NNN)NNrf   )NF)NNFFNN)NNFF)Q__doc__Zpythran.backendr   r   Zpythran.configr   Zpythran.cxxgenr   r   r   r   r	   r
   r   r   r   Zpythran.distr   r   Zpythran.middlendr   r   Zpythran.passmanagerr   Zpythran.tablesr   Zpythran.typesr   Zpythran.types.type_dependenciesr   Zpythran.types.conversionr   r   r   r   r   Zpythran.syntaxr   r   r   Zpythran.versionr   Zpythran.utilsr   Zpythran.frontendrX   r    Zdistutils.errorsr!   Z	distutilsr"   Znumpy.distutils.corer#   Ztempfiler$   r%   ZgastrP   r   os.pathr   r   r   r   	functoolsr&   r   Z	getLoggerr   r7   r@   rI   rU   rb   re   r   r   r   r   r   r   r(   r(   r(   r*   <module>   sn    



 
!
=
?
: