o
    2                     @   s   d 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 G dd deZG dd deZG dd deZG dd deZdS )a  Cloud resource filter expression rewrite backend classes.

These classes are alternate resource_filter.Compile backends that rewrite
expressions instead of evaluating them. To rewrite a filter expression string:

  rewriter = resource_expr_rewrite.Backend()
  frontend_expr, backend_expr = rewriter.Rewrite(filter_expression_string)

It is possible for a rewritten expression to collapse to None. This means that
there is no equivalent server-side expression, i.e., no server-side pruning is
possible.

These rewrites can only prune expressions that will be False client-side.
In this sense a rewrite => None means "the client side will figure it out".
This results in a backend expression that can be applied server-side to prune
the resources passed back to the client-side, where the full filter expression
is applied. The result will be the same whether or not the backend filter is
applied. The only difference would be the number of resources transmitted
from the server back to the client.

None is the value for keys and operators not supported by the backend.
ExprTRUE, ExprAND, ExprOR and ExprNOT do expression rewrites based on None:

  TRUE => None
  None AND x => x
  x AND None => x
  x OR None => None
  None OR x => None
  NOT None => None
    )absolute_import)division)unicode_literals)resource_exceptions)resource_filter)resource_lex)resource_projection_spec)resource_property)resource_transformc                   @   s    e Zd ZdZdd Zdd ZdS )_ExprzHAn expression rewrite object that evaluates to the rewritten expression.c                 C   s
   || _ d S Nexprselfr    r   O/tmp/google-cloud-sdk/lib/googlecloudsdk/core/resource/resource_expr_rewrite.py__init__>   s   
z_Expr.__init__c                 C   s   | j S )z@Returns the server side string rewrite of the filter expression.r   r   r   r   r   RewriteA   s   z_Expr.RewriteN)__name__
__module____qualname____doc__r   r   r   r   r   r   r   ;   s    r   c                   @   s   e Zd ZdZdddZdS )
_BelieveMez3A symbols dict with nothing that claims everything.Nc                 C   s
   ~~| j S r   )get)r   objtyper   r   r   r   I   s   z_BelieveMe.getr   )r   r   r   r   r   r   r   r   r   r   F   s    r   c                   @   s  e Zd ZdZd>ddZd?ddZdd Zd	d
 Zdd Zdd Z	dd Z
dd Z	d?ddZdd Zd@ddZd@ddZdd Zdd Zd d! Zd"d# Zd$d% Zd&d' Zd(d) Zd>d*d+Zd>d,d-Zd>d.d/Zd>d0d1Zd>d2d3Zd>d4d5Zd>d6d7Zd>d8d9Zd>d:d;Zd<d= Z dS )ABackendBaseax  Cloud resource filter expression rewrite backend base.

  All rewrites default to None. Use this class for target expressions that
  implement a small subset of OnePlatform expressions.

  Attributes:
    frontend_fields: A set of dotted field names supported in the frontend.
    message: The resource proto message object that describes all fields
      available in the backend.
    partial_rewrite: True if the most recent Rewrite() backend_expression is
      a partial rewrite of the original expression. False means that the entire
      original expression was rewritten and that frontend_expression can be
      ignored.
  Nc                 C   s   || _ || _d| _d S )NF)frontend_fieldsmessagepartial_rewrite)r   r   r    r   r   r   r   ^   s   
zBackendBase.__init__c                 C   s   |r|j r|j td}t|dr|jr|dfS d| _tj|d}t	 |_ t
j|| |d }| jr6|nd}|r@| r@d}||fS )a  Returns (frontend_expression, backend_expression) for expression.

    There are 3 outcomes:
      (None, backend) -- only need to apply the backend expression
      (frontend, None) -- only need to apply the frontend expression
      (frontend, backend) -- must apply both frontend and backend expressions

    Args:
      expression: The expression string to rewrite.
      defaults: resource_projection_spec.ProjectionSpec defaults.

    Returns:
      Returns (frontend_expression, backend_expression) for expression.
    conditionalsflattenNF)defaults)backendr$   )symbolsr   r
   GetTypeDataNamehasattrr#   r!   r   ProjectionSpecr   r   Compiler   isspace)r   
expressionr$   r"   backend_expressionfrontend_expressionr   r   r   r   c   s$   
zBackendBase.Rewritec                 C   s   |sd| _ t|S NT)r!   r   r   r   r   r   Expr   s   zBackendBase.Exprc                 C      dS )Rewrites <left AND right>.Nr   r   unused_leftunused_rightr   r   r   
RewriteAND      zBackendBase.RewriteANDc                 C   r1   )Rewrites <left OR right>.Nr   r3   r   r   r   	RewriteOR   r7   zBackendBase.RewriteORc                 C   r1   )zRewrites <NOT expr>.Nr   )r   unused_exprr   r   r   
RewriteNOT   r7   zBackendBase.RewriteNOTc                 C   r1   )z#Rewrites global restriction <call>.Nr   )r   unused_callr   r   r   RewriteGlobal   r7   zBackendBase.RewriteGlobalc                 C   r1   )Rewrites an operand.Nr   )r   unused_operandr   r   r   RewriteOperand   r7   zBackendBase.RewriteOperandc                 C   r1   )Rewrites <key op operand>.Nr   )r   
unused_key	unused_opr?   unused_key_typer   r   r   RewriteTerm   s   zBackendBase.RewriteTermc                 C   s:   t |}	 |jddd}|s	 |S |dv rdj|dS q)z;Returns expression enclosed in (...) if it contains AND/OR.Tz ())balance_parens)ANDORz({expression})r,   )r   LexerTokenformat)r   r,   lextokr   r   r   Parenthesize   s   
zBackendBase.ParenthesizeFc                 C   s   zt t|W S  ty   Y nw zt t|W S  ty!   Y nw g }|}d}|D ]9}|r1d}n-|dkrD|| || d}d}n|dkrP|d d}n| s\|dks\|dkr^d}|| q*d|}|rqdj|d	S |S )
a(  Returns value or value "..." quoted with C-style escapes if needed.

    Args:
      value: The string value to quote if needed.
      always: Always quote non-numeric value if True.

    Returns:
      A string: value or value "..." quoted with C-style escapes if needed or
      requested.
    F\T"': z
"{string}")string)strint
ValueErrorfloatappendr+   joinrL   )r   valuealwayscharsencloseescapedcrU   r   r   r   Quote   s:   



zBackendBase.Quotec                    sH   t |tr fdd|D }dddd |D  d S j| dS )a  Returns operand enclosed in "..." if necessary.

    Args:
      operand: A string operand or list of string operands. If a list then each
        list item is quoted.
      always: Always quote if True.

    Returns:
      A string: operand enclosed in "..." if necessary.
    c                    s   g | ]	}j | d qS )r]   )rb   .0xr]   r   r   r   
<listcomp>   s    z,BackendBase.QuoteOperand.<locals>.<listcomp>(,c                 S   s   g | ]}|d ur|qS r   r   rd   r   r   r   rh      s    )rc   )
isinstancelistr[   rb   )r   operandr]   operandsr   rg   r   QuoteOperand   s   
zBackendBase.QuoteOperandc                 C   s   |s|r	|  dS t|}| jrEzt|| j\}}W n" ty>   | jdur7t|| js7t	
d||  d Y S w t|}nd}|  | ||||S )a  Returns the rewritten backend term expression.

    Args:
      key: The parsed key.
      op: The operator name.
      operand: The operand.
      transform: The transform object if a transform was specified.
      args: The transform args if a transform was specified.

    Raises:
      UnknownFieldError: If key is not supported on the frontend and backend.

    Returns:
      The rewritten backend term expression.
    Nz!Unknown field [{}] in expression.)r0   r   
GetKeyNamer    r	   GetMessageFieldTypeKeyErrorr   LookupFieldr   UnknownFieldErrorrL   rE   )r   keyoprn   	transformargskey_namekey_typer   r   r   Term   s(   


	zBackendBase.Termc                 C   s   t d S r   )r   r   r   r   r   ExprTRUE  s   zBackendBase.ExprTRUEc                 C   sZ   |r|  }|r|  }|sd| _|r| |S dS |s$d| _| |S | | ||S )zReturns an AND expression node.TNF)r   r!   r0   completer6   r   leftrightr   r   r   ExprAND  s   
zBackendBase.ExprANDc                 C   sF   |r|  }|s| dS |r|  }|s| dS | | ||S )zReturns an OR expression node.N)r   r0   r9   r   r   r   r   ExprOR%  s   

zBackendBase.ExprORc                 C   s*   |r|  }|s| d S | | |S r   )r   r0   r;   r   r   r   r   ExprNOT3  s
   
zBackendBase.ExprNOTc                 C   s   |  | |S r   )r0   r=   )r   callr   r   r   
ExprGlobal:  s   zBackendBase.ExprGlobalc                 C   s   |S r   r   )r   r\   r   r   r   ExprOperand=     zBackendBase.ExprOperandc                 C      |  |d|||S )N<r|   r   rv   rn   rx   ry   r   r   r   ExprLT@     zBackendBase.ExprLTc                 C   r   )Nz<=r   r   r   r   r   ExprLEC  r   zBackendBase.ExprLEc                 C   r   )NrS   r   r   r   r   r   ExprHASF  r   zBackendBase.ExprHASc                 C   r   )N=r   r   r   r   r   ExprEQI  r   zBackendBase.ExprEQc                 C   r   )Nz!=r   r   r   r   r   ExprNEL  r   zBackendBase.ExprNEc                 C   r   )Nz>=r   r   r   r   r   ExprGEO  r   zBackendBase.ExprGEc                 C   r   )N>r   r   r   r   r   ExprGTR  r   zBackendBase.ExprGTc                 C   r   )N~r   r   r   r   r   ExprREU  r   zBackendBase.ExprREc                 C   r   )N!~r   r   r   r   r   	ExprNotREX  r   zBackendBase.ExprNotREc                 C   r1   r/   r   r   r   r   r   
IsRewriter[  r   zBackendBase.IsRewriter)NNr   )F)!r   r   r   r   r   r   r0   r6   r9   r;   r=   r@   rE   rO   rb   rp   r|   r}   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   N   s@    




++








r   c                   @   s8   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdS )Backenda[  Rewrites for OnePlatform server side filter expressions.

  This class rewrites client side expressions to OnePlatform server side
  expressions. The only difference is the server side does not support the
  regular expression ~ and !~ operators. Use this class for target expressions
  that implement a large subset of OnePlatform expressions.
  c                 C      dj | || |dS )r2   z{left} AND {right}r   r   rL   rO   r   r   r   r   r6   h     zBackend.RewriteANDc                 C   r   )r8   z{left} OR {right}r   r   r   r   r   r   r9   m  r   zBackend.RewriteORc                 C   s   dj | |dS )zRewrites <NOT expression>.zNOT {expression}rI   r   )r   r,   r   r   r   r;   r  s   zBackend.RewriteNOTc                 C   s
   |  |S )r>   )rp   )r   rn   r   r   r   r@   v  s   
zBackend.RewriteOperandc                 C   s4   ~|dv rdS |  |}|du rdS dj|||dS )rA   )r   r   Nz{key}{op}{operand})rv   rw   rn   )r@   rL   )r   rv   rw   rn   r{   argr   r   r   rE   z  s   
zBackend.RewriteTermN)	r   r   r   r   r6   r9   r;   r@   rE   r   r   r   r   r   _  s    r   N)r   
__future__r   r   r   googlecloudsdk.core.resourcer   r   r   r   r	   r
   objectr   dictr   r   r   r   r   r   r   <module>   s      