o
    ,wi                     @   s   d Z ddlZddlZddlZddlZddlmZmZ edZ	edZ
edZdedefd	d
ZdedefddZdedee fddZejG dd dZdS )a  Manages a namespace to avoid conflicting names.

Generally, when generating code, we do not want variables names to conflict.
This class helps manage names in scope, and for simplicity we try to avoid
conflicts between globals/non-locals/locals, even if they might work when run.
    N)OptionalSetz(?<=.)([A-Z])z[^a-z_0-9]+z[a-z][a-z_0-9]+namereturnc                 C   s   t dd |  S )z:Converts a camel or studly-caps name to a snake_case name.c                 S   s   d|  d S )N_r   )group)m r	   Z/home/ubuntu/sommelier/.venv/lib/python3.10/site-packages/fiddle/_src/codegen/namespace.py<lambda>$   s    z camel_to_snake.<locals>.<lambda>)_CAMEL_TO_SNAKE_REsublowerr   r	   r	   r
   camel_to_snake"   s   r   c                 C   s   t d| S )z@Removes invalid characters such as whitespace, parenthesis, etc. )_PY_VAR_NAME_INVALID_REr   r   r	   r	   r
   valid_name_chars'   s   r   c                 C   s(   t t| } t| }|r|dS dS )zCReturns a sanitized, lower-case version of `name` for py variables.r   N)r   r   _PY_VAR_NAME_REsearchr   )r   matchr	   r	   r
   py_var_name,   s   
r   c                   @   sd   e Zd ZU dZejdd dZee e	d< dede
fdd	Zd
edefddZdedefddZdS )	NamespacezManages active Python instance names.

  By default, the namespace will be populated with Python keywords. If you do
  not want this, then initialize `names` manually to the empty set.
  c                   C   s
   t tjS )N)setkeywordkwlistr	   r	   r	   r
   r   <   s   
 zNamespace.<lambda>)default_factorynameskeyr   c                 C   s
   || j v S )zReturns True if a name is already defined.

    In the default Namespace() constructor, names include keywords.

    Args:
      key: Name to check.
    )r   )selfr   r	   r	   r
   __contains__>   s   
zNamespace.__contains__r   c                 C   s*   || j v rtd|d| j | |S )zBAdds a name and returns it, raising an error if it already exists.zTried to add z) (e.g. an import), but it already exists!)r   
ValueErroradd)r   r   r	   r	   r
   r"   H   s   

zNamespace.addprefixc                 C   sf   |t | }|| jvr| |S tjddD ]}| d| | jvr.| | d|   S qtd)a  Generates a new name for a given instance.

    This method adds the new name to the namespace.

    Example:
      self.names = ["foo"]
      get_new_name("bar", "shared_") == "shared_bar"

    Example 2:
      self.names = ["shared_foo", "bar"]
      get_new_name("Foo", "shared_") == "shared_foo_2"

    Args:
      base_name: Base name to derive a new name for. This will be converted to
        snake case automatically.
      prefix: Prefix to prepend to any names.

    Returns:
      A new unique name.
       )startr   z.pytype helper -- itertools.count() is infinite)r   r   r"   	itertoolscountAssertionError)r   	base_namer#   r   ir	   r	   r
   get_new_nameP   s   

zNamespace.get_new_nameN)__name__
__module____qualname____doc__dataclassesfieldr   r   str__annotations__boolr    r"   r+   r	   r	   r	   r
   r   3   s   
 
r   )r/   r0   r&   r   retypingr   r   compiler   r   r   r2   r   r   r   	dataclassr   r	   r	   r	   r
   <module>   s   


