o
    ,wiJ                     @   s  d Z ddlZddlZddlZddlZddlZddlmZmZm	Z	m
Z
mZ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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Z ej!ddG dd dZ"de
e" de#de
e# fddZ$de
e" de
e# fddZ%					dLdej&dede#de#deej' ded  fd!d"Z(de#de#d#e
e j) d$e*de j+f
d%d&Z,eege j)f Z-d'ee d(e
e# d)e-de
e j) fd*d+Z.de#d,e	ej/e#f d)e-de
e j) fd-d.Z0dej&deej/ fd/d0Z1d1eej/ d2efd3d4Z2e
eej/e
ej3 f  Z4dej&de4fd5d6Z5dej&de#d,e	ej/e#f d)e-de
e j) f
d7d8Z6d9e j)d:ej7d)e-de j)fd;d<Z8d=e#d>ej/d)e-fd?d@Z9d=e#de#fdAdBZ:dCede#fdDdEZ;d>ej/de#fdFdGZ<de j)fdHdIZ=de j)fdJdKZ>dS )Mz6Library for converting generating fiddlers from diffs.    N)AnyCallableDictListLiteralOptionalSetTuple)daglish)diffing)config)mutate_buildable)taggingimport_manager	namespace)py_val_to_cst_converter)daglish_legacyT)frozenc                   @   s(   e Zd ZU eed< ejed< dd ZdS )ObjectToNameprefixpathc                 C   s   t | S N)id)self r   ]/home/ubuntu/sommelier/.venv/lib/python3.10/site-packages/fiddle/_src/codegen/codegen_diff.py__hash__*   s   zObjectToName.__hash__N)__name__
__module____qualname__str__annotations__r
   Pathr   r   r   r   r   r   %   s   
 
r   all_to_name
param_namereturnc                    s    fdd| D S ).Returns suggested names for a list of objects.c                    s$   g | ]}|j   d  t|j qS )_)r   _path_to_namer   .0to_namer&   r   r   
<listcomp>2   s    z)assign_explicit_names.<locals>.<listcomp>r   )r%   r&   r   r.   r   assign_explicit_names.   s   
r0   c                    s   i }| D ]}|j dd }||jt| g | qi  | D ]&\}}t|dkr3| |d < q"|D ]}|j dd }|jt|  |< q5q" fdd| D S )r(   N   r   c                    s   g | ]} | qS r   r   r+   result_as_dictr   r   r/   I   s    z&assign_short_names.<locals>.<listcomp>)r   
setdefaultr   r*   appenditemslen)r%   name_to_pathsr-   sub_pathnamegroupr   r4   r   assign_short_names8   s    
r>   fiddlercfgexplicitdiffold	func_namer   variable_naming)rA   shortc              
      s  |du rt  | | t}n|j| | t| }g }|durctdd | jD  t	 | t
|tjdD ]t fddttd D ra|td qEnt
|tjdD ]
|td	 qj|d
krt||}nt|}fddt||D }	fdd| jD }
tjdd dtjt|ddtjtjdtjt||	|
ddg}tjtj|d}g }|t| j|
|7 }|t ||	|7 }|t!| ||	|7 }t"|||t#|j$}t%j&|' |g d}|S )as  Returns the CST for a fiddler function that applies the changes in `diff`.

  The returned `cst.Module` consists of a set of `import` statements for any
  necessary imports, followed by a function definition for a function whose
  name is `func_name`, which takes a single parameter named `param_name`
  containing a `fdl.Config` (or other `Buildable` or structure), and mutates
  that `Config` in-place as described by `diff`.

  The body of the returned function has three sections:

  * The first section creates variables for any new shared values that are
    added by the diff (i.e., values in `diff.new_shared_values`).
  * The second section creates variables to act as aliases for values in the
    in the input `Config`.  This ensures that we can still reference those
    values even after we've made mutations to the `Config` that might make
    them unreachable from their original location.
  * The final section modifies the `Config` in-place, as described by
    `diff.changes`.  Changes are grouped by the parent object that they modify.
    This section contains one statement for each change.

  Args:
    diff: A `fdl.Diff` describing the change that should be made by the fiddler
      function.
    old: The original config that is transformed by `diff`.  If specified, then
      this is used when creating aliases for values in the input `Config` to
      determine which paths need to have aliases created.  (In particular, it is
      used to determine which paths are aliases for one another.)  If not
      specified, then pessimistically assume that aliases must be created for
      all referenced paths.
    func_name: The name for the fiddler function.
    param_name: The name for the parameter to the fiddler function.
    import_manager: Existing import manager. Usually set to None, but if you are
      integrating this with other code generation tasks, it can be nice to
      share.
    variable_naming: Whether to create intermediate variables with long,
      explicit names, or just capture the last elements of a path.

  Returns:
    An `cst.Module` object.  You can convert this to a string using
    `result.code`.
  Nc                 S   s   g | ]}|j qS r   targetr,   changer   r   r   r/          z%fiddler_from_diff.<locals>.<listcomp>keyc                 3   s     | ]}d |  v V  qd S r   r   )r,   i)modified_pathsr   r   r   	<genexpr>   s    z$fiddler_from_diff.<locals>.<genexpr>r2   moved_	original_rA   c                    s"   i | ]\}}|j  j|d dqS ) )r   )r   get_new_name)r,   r-   r<   r   r   r   
<dictcomp>   s    z%fiddler_from_diff.<locals>.<dictcomp>c                    s   g | ]
}  t|d qS )shared_)rT   _name_for_value)r,   valuer   r   r   r/      s    c                 S   s   t | tjS r   )
isinstancetypes
ModuleTyperX   r   r   r   <lambda>   s    z#fiddler_from_diff.<locals>.<lambda>   r   )matcherpriority	converter)r&   moved_value_namesnew_shared_value_names)additional_converters)body)(namespace_lib	Namespaceaddimport_manager_libImportManagerr   _find_used_pathssetchanges_add_path_aliasessortedr
   path_stranyranger9   r7   r   r0   r>   zipnew_shared_valuesr   ValueConverter	functoolspartial_convert_moduler   	Reference_convert_referenceconvert_py_val_to_cst#_cst_for_new_shared_value_variables_cst_for_moved_value_variables_cst_for_changes_cst_for_fiddlerboolimports_by_full_namecstModulesorted_import_lines)rB   rC   rD   r&   r   rE   
used_pathsmoved_values_to_nameinitial_namesrb   rc   value_converterspyval_to_cstre   r?   resultr   )rO   r   r   r   fiddler_from_diffL   s   1




$

r   re   add_leading_blank_linec                 C   sJ   t jt | t jt jt |ddgdt ||r!t  gdS g dS )a  Returns an `cst.FunctionDef` for the fiddler function.

  Args:
    func_name: The name of the fiddler function.
    param_name: The name of the fiddler function's parameter.
    body: The body of the fiddler function.
    add_leading_blank_line: If true, add a leading blank line.
  rS   )r<   star)params)r<   r   re   leading_lines)r   FunctionDefName
ParametersParamIndentedBlock	EmptyLine)rD   r&   re   r   r   r   r   r      s   
r   valuesnamesr   c                 C   sZ   g }t t| |dd dD ]\}}|tjtjt|dg||d qdd |D S )zEReturns a list of `CSTNode`s for creating new shared value variables.c                 S   s   | d S )Nr2   r   itemr   r   r   r]      s    z5_cst_for_new_shared_value_variables.<locals>.<lambda>rL   rG   targetsrX   c                 S      g | ]}t |gqS r   r   SimpleStatementLiner,   stmtr   r   r   r/          z7_cst_for_new_shared_value_variables.<locals>.<listcomp>)ro   rs   r7   r   AssignAssignTargetr   )r   r   r   
statementsrX   r<   r   r   r   r|      s   r|   rb   c              	   C   s`   g }t | dd d}|D ]\}}|tjtjt|dgt| ||d qdd |D S )zFReturns a list of `CSTNode`s for creating moved value alias variables.c                 S      t | d S Nr   r
   rp   r   r   r   r   r]          z0_cst_for_moved_value_variables.<locals>.<lambda>rL   rG   r   c                 S   r   r   r   r   r   r   r   r/      r   z2_cst_for_moved_value_variables.<locals>.<listcomp>)ro   r8   r7   r   r   r   r   _cst_for_path)r&   rb   r   r   sorted_moved_value_namesr   r<   r   r   r   r}      s   
r}   c                    s^   t dd | jD   fdd}| jD ]}t|tjtjfr%t||j qt|| j	  S )a  Returns a list of paths referenced in `diff`.

  This list includes paths for any values we might need to create aliases
  for, if that value moved.  In particular, it includes the parent path
  for each change in `diff.changes`, plus the target path for any
  `diff.Reference` in `diff` whose root is `'old'`.

  Args:
    diff: The `fdl.Diff` that should be scanned for used paths.
  c                 s   s    | ]
}|j d d V  qd S )Nr1   rG   rI   r   r   r   rP     s    z#_find_used_paths.<locals>.<genexpr>c                 3   s8    ~ d V  t |tjr|jdkr |j d S d S d S )NrC   )rY   r   ry   rootrh   rH   )r   noder   r   r   collect_ref_targets  s   z-_find_used_paths.<locals>.collect_ref_targets)
rl   rm   rY   r   SetValueModifyValuer   traverse_with_path	new_valuert   )rB   r   rJ   r   r   r   rk     s   
rk   paths	structurec                 C   sT   t j|dd}t j|dd}t| D ]}||d}|dur'| |t|  qdS )a  Update `paths` to include any other paths that reach the same objects.

  If any value `v` reachable by a path `p` in `paths` is also reachable by one
  or more other paths, then add those paths to `paths`.  E.g., if a shared
  object is reachable by paths `.x.y` and `.x.z', and `paths` includes
  only `.x.y`, then this will add `.x.z` to `paths`.

  Args:
    paths: A set of paths to values in `structure`.
    structure: The structure used to determine the paths for shared values.
  T)memoizable_onlyN)r   collect_value_by_pathcollect_paths_by_idlistgetupdater   )r   r   path_to_valueid_to_pathsr   rX   r   r   r   rn      s   rn   c                 C   sR   t t}| jD ]}|j}|std||dd  | qt| dd dS )zDReturns a sorted list of changes in `diff`, grouped by their parent.z)Changing the root object is not supportedNr1   c                 S   r   r   r   r   r   r   r   r]   F  r   z*_group_changes_by_parent.<locals>.<lambda>rL   )	collectionsdefaultdictr   rm   rH   
ValueErrorr7   ro   r8   )rB   changes_by_parentrJ   r   r   r   r   _group_changes_by_parent:  s   

r   c                 C   s   g }t | D ]\}}||v rt|| }nt|||}g }d}	g }
|D ]}|jd }t|||}t|tjrat|t	j
s@J |	du sFJ ||j}ttj|tjt|t|gd}	q%t|t	jrq|tj|d q%t|t	jr|jd j}|ttj|tjt|t||t||jgd q%t|t	jt	j
fr||j}|
tjt|g|d q%t|t	jr|jd j}|
tjtj|tjt|t||t||jgdd q%tdt| | | |	dur||	 | |
 qdd	 |D S )
a  Returns a list of CST nodes that apply the changes described in `diff`.

  Args:
    diff: The `fdl.Diff` whose changes should be applied.
    param_name: The name of the parameter to the fiddler function.
    moved_value_names: Dictionary mapping any paths that might become
      unreachable once the config is mutated to alias variables that can be used
      to reach those values.
    pyval_to_cst: A function used to convert Python values to CST.
  Nr1   )funcargsrG   r   r\   zUnsupported DiffOperation c                 S   r   r   r   r   r   r   r   r/     r   z$_cst_for_changes.<locals>.<listcomp>)!r   r   r   r   rH   _cst_for_childrY   r
   BuildableFnOrClsr   r   r   ExprCallr   update_callableArgDeleteValuer7   Del	RemoveTagr<   r   
remove_tagtagr   r   r   AddTagadd_tagr   typeextend)rB   r&   rb   r   re   parent_pathrm   
parent_cstdeletesr   assignsrJ   child_path_elt	child_cstnew_value_cstarg_namer   r   r   r~   I  s|   





r~   r   r   c                 C   s   t |tjrtj| t|jdS t |tjr+||j}tj	| tj
t|dgdS t |tjrE||j}tj	| tj
t|dgdS tdt| )a  Returns a CST expression that can be used to access a child of a parent.

  Args:
    parent_cst: CST expression for the parent object.
    child_path_elt: A PathElement specifying a child of the parent.
    pyval_to_cst: A function used to convert Python values to CST.
  )rX   attr)slice)rX   r   zUnsupported PathElement )rY   r
   Attrr   	Attributer   r<   Indexindex	SubscriptSubscriptElementKeyrM   r   r   )r   r   r   	index_cstkey_cstr   r   r   r     s   	

r   r<   r   c                 C   s$   t | }|D ]}t|||}q|S )z9Converts a `daglish.Path` to an `cst.CSTNode` expression.)r   r   r   )r<   r   r   r   path_eltr   r   r   r     s   
r   c                 C   s   t ddd |  S )z:Converts a camel or studly-caps name to a snake_case name.z(?<=.)([A-Z])c                 S   s   d|  d  S )Nr)   r   )r=   lower)mr   r   r   r]     rK   z!_camel_to_snake.<locals>.<lambda>)resubr   )r<   r   r   r   _camel_to_snake  s
   r   rX   c                 C   s*   t | tjrtt| jS tt| jS )z.Returns a name for a value, based on its type.)rY   
config_lib	Buildabler   get_callabler   r   r\   r   r   r   rW     s   rW   c                 C   s&   t | }tdd|}|d S )z#Converts a path to a variable name.z[^a-zA-Z_0-9]+r)   )r
   rp   r   r   stripr   )r   r<   r   r   r   r*     s   
r*   c                 C   sn   | j dkr| j|v rt|| j S t|| j|S t| jd tjs$J || jd j }t|| jdd |S )z+Converts a `Reference` to a CST expression.rC   r   r2   N)	r   rH   r   r   r   rY   r
   r   r   )rX   convert_childr&   rb   rc   var_namer   r   r   rz     s   

rz   c                 C   s   ~| | j}t|S )z1Converts a Module to CST, using an ImportManager.)add_by_namer   r   dotted_name_to_cst)rX   r   r   r<   r   r   r   rx     s   
rx   )Nr?   r@   NrA   )?__doc__r   dataclassesrv   r   rZ   typingr   r   r   r   r   r   r   r	   fiddler
   r   fiddle._srcr   r   r   r   fiddle._src.codegenr   ri   r   rf   r   fiddle._src.experimentalr   libcstr   	dataclassr   r"   r0   r>   Diffrj   r   CSTNoder   r   r   PyValToCstFuncr|   r$   r}   rk   rn   DiffOperationChangesByParentr   r~   PathElementr   r   r   rW   r*   rz   rx   r   r   r   r   <module>   s   (



 



a

