
    	^cU<                     p    d dl Z d dlZddlmZ ddlmZmZ ddlmZ d Z		 	 	 	 	 	 	 dd
Z
	 	 	 	 	 	 	 ddZdS )    N   )_)errorpycompat)
stringutilc              #   n  K   | sdS t          j        t          j        t          j        z             i ddfdt          j        |           fdfdfdfd}             }|d	k    r|t          j        t          j                  v r*             }|t          j        t          j                  v *|d
k    rdgffV  dz               }n<|dk    rg              t          j        t          j                            \  }}t          |          }t          d|          D ]}dgffV  dz  n|dv rw|dk    r
             } ||          \  }}|g}|dk    r1 |                       \  }}|	                    |           |dk    1fd|D             }d|ffV  dz  nT|dk    r# |                       \  }}	 |	          n+|dk    r% |                       \  }}
|
<   d|
ffV  n |dk    r |                       \  }}d|fV  n|dk    rO             }|dk    r*d}             }|dvr||z  }             }|dvd|fV  n ||          \  }}d|fV  n|dk    r|dvr             }|dvno|dk    rd             }n\|d	k    rdS d}d}|d	k    r&|dk     r ||z  }|dz  }             }|d	k    r|dk      t          j        t          d          |z            |d	k    dS dS ) a#  parses a DAG from a concise textual description; generates events

    "+n" is a linear run of n nodes based on the current default parent
    "." is a single node based on the current default parent
    "$" resets the default parent to -1 (implied at the start);
        otherwise the default parent is always the last node created
    "<p" sets the default parent to the backref p
    "*p" is a fork at parent p, where p is a backref
    "*p1/p2/.../pn" is a merge of parents p1..pn, where the pi are backrefs
    "/p2/.../pn" is a merge of the preceding node and p2..pn
    ":name" defines a label for the preceding node; labels can be redefined
    "@text" emits an annotation event for text
    "!command" emits an action event for the current node
    "!!my command
" is like "!", but to the end of the line
    "#...
" is a comment up to the end of the line

    Whitespace between the above elements is ignored.

    A backref is either
     * a number n, which references the node curr-n, where curr is the current
       node, or
     * the name of a label you placed earlier using ":name", or
     * empty to denote the default parent.

    All string valued-elements are either strictly alphanumeric, or must
    be enclosed in double quotes ("..."), with "" as escape character.

    Generates sequence of

      ('n', (id, [parentids])) for node creation
      ('l', (id, labelname)) for labels on nodes
      ('a', text) for annotations
      ('c', command) for actions (!)
      ('C', command) for line actions (!!)

    Examples
    --------

    Example of a complex graph (output not shown for brevity):

        >>> len(list(parsedag(b"""
        ...
        ... +3         # 3 nodes in linear run
        ... :forkhere  # a label for the last of the 3 nodes from above
        ... +5         # 5 more nodes on one branch
        ... :mergethis # label again
        ... <forkhere  # set default parent to labeled fork node
        ... +10        # 10 more nodes on a parallel branch
        ... @stable    # following nodes will be annotated as "stable"
        ... +5         # 5 nodes in stable
        ... !addfile   # custom command; could trigger new file in next node
        ... +2         # two more nodes
        ... /mergethis # merge last node with labeled node
        ... +4         # 4 more nodes descending from merge node
        ...
        ... """)))
        34

    Empty list:

        >>> list(parsedag(b""))
        []

    A simple linear run:

        >>> list(parsedag(b"+3"))
        [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [1]))]

    Some non-standard ways to define such runs:

        >>> list(parsedag(b"+1+2"))
        [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [1]))]

        >>> list(parsedag(b"+1*1*"))
        [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [1]))]

        >>> list(parsedag(b"*"))
        [('n', (0, [-1]))]

        >>> list(parsedag(b"..."))
        [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [1]))]

    A fork and a join, using numeric back references:

        >>> list(parsedag(b"+2*2*/2"))
        [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [0])), ('n', (3, [2, 1]))]

        >>> list(parsedag(b"+2<2+1/2"))
        [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [0])), ('n', (3, [2, 1]))]

    Placing a label:

        >>> list(parsedag(b"+1 :mylabel +1"))
        [('n', (0, [-1])), ('l', (0, 'mylabel')), ('n', (1, [0]))]

    An empty label (silly, really):

        >>> list(parsedag(b"+1:+1"))
        [('n', (0, [-1])), ('l', (0, '')), ('n', (1, [0]))]

    Fork and join, but with labels instead of numeric back references:

        >>> list(parsedag(b"+1:f +1:p2 *f */p2"))
        [('n', (0, [-1])), ('l', (0, 'f')), ('n', (1, [0])), ('l', (1, 'p2')),
         ('n', (2, [0])), ('n', (3, [2, 1]))]

        >>> list(parsedag(b"+1:f +1:p2 <f +1 /p2"))
        [('n', (0, [-1])), ('l', (0, 'f')), ('n', (1, [0])), ('l', (1, 'p2')),
         ('n', (2, [0])), ('n', (3, [2, 1]))]

    Restarting from the root:

        >>> list(parsedag(b"+1 $ +1"))
        [('n', (0, [-1])), ('n', (1, [-1]))]

    Annotations, which are meant to introduce sticky state for subsequent nodes:

        >>> list(parsedag(b"+1 @ann +1"))
        [('n', (0, [-1])), ('a', 'ann'), ('n', (1, [0]))]

        >>> list(parsedag(b'+1 @"my annotation" +1'))
        [('n', (0, [-1])), ('a', 'my annotation'), ('n', (1, [0]))]

    Commands, which are meant to operate on the most recently created node:

        >>> list(parsedag(b"+1 !cmd +1"))
        [('n', (0, [-1])), ('c', 'cmd'), ('n', (1, [0]))]

        >>> list(parsedag(b'+1 !"my command" +1'))
        [('n', (0, [-1])), ('c', 'my command'), ('n', (1, [0]))]

        >>> list(parsedag(b'+1 !!my command line\n +1'))
        [('n', (0, [-1])), ('C', 'my command line'), ('n', (1, [0]))]

    Comments, which extend to the end of the line:

        >>> list(parsedag(b'+1 # comment\n+1'))
        [('n', (0, [-1])), ('n', (1, [0]))]

    Error:

        >>> try: list(parsedag(b'+1 bad'))
        ... except Exception as e: print(pycompat.sysstr(bytes(e)))
        invalid character in dag description: bad...

    Nr   c                     | sS | d         t          j        t          j                  v rt	          |           z
  S |          S )Nr   )r   bytestrstringdigitsint)reflabelsp1rs    5/usr/lib/python3/dist-packages/mercurial/dagparser.pyresolvezparsedag.<locals>.resolve   sF     	IVx'6666s3xx<#;    c                  $    t           d          S )N    )next)chiters   r   nextchzparsedag.<locals>.nextch   s    FE"""r   c                 >    d}| |v r|| z  }             } | |v | |fS Nr    )callowsr   s      r   nextrunzparsedag.<locals>.nextrun   s;    5jjFAA 5jj !tr   c                 v    d}| |k    r%| |k    r
             } || z  }             } | |k    %             |fS r   r   )r   limitescaper    r   s       r   nextdelimitedzparsedag.<locals>.nextdelimited   sV    5jjF{{FHHFAA	 5jj
 vxx{r   c                 R    | dk    r              dd          S  |           S )N   "   \r   )r   r   r%   r!   	wordcharss    r   
nextstringzparsedag.<locals>.nextstring   s8    99 =477771i(((r   r      .   nr      +s   */   *   /c                 &    g | ]} |          S r   r   ).0r   r   s     r   
<listcomp>zparsedag.<locals>.<listcomp>   s!    0003''#,,000r      <   :   l   @   a   !r   s   
    C   c   #   $
   s+   invalid character in dag description: %s...)r   r   r   ascii_lettersr   iterbytestr
whitespacer   rangeappendr   Abortr   )descr*   r   digsniprefprefspsr   nametextcmdr    r   r   r   r%   r!   r   r   r   r)   s                 @@@@@@@@@r   parsedagrN      s     f    !5!EFFI F	B	A       !$''F# # # # #        ) ) ) ) ) ) ) ) 	A
u**8#F$56666A 8#F$56666 99RD	/!!!BFAAA$YYgffhh(8(G(GHHGAtD		A1a[[  QIo%%%Q %ZZDyyFHH jmmGAtFEt))$*VVXX..4T""" t)) 1000%000BB-BFAA$YYZ))FAsBB$YY j**GAtF4LT
"""""$YY j**GAt*$YYADyyFHHy((1HCA y(( Ci#A3Ci$YY9$$FHH 9$$$YYBAA%ZZFAAu**RQQFHH u**R +@AAAE  I u******r   TFF   c              #       K   d  fd}d}	 |            D ]O}
|
dk    r	|	r|	V  d}	t          |	          t          |
          z   |k    r|	V  d}	n|r|	r|
dk    r|	dz  }	|	|
z  }	P|	r|	V  dS dS )z$generates single lines for dagtext()c                     t          j        d|           r| S d|                     dd                              dd          z   dz   S )Ns   ^[0-9a-z]*$r'   r(   s   \\)rematchreplace)rL   s    r   
wrapstringz dagtextlines.<locals>.wrapstring-  sI    8ND)) 	Kdll5'22::4GGG$NNr   c               3     K   i } d}d}d}D ]E\  }}|dk    rd|\  }}||k    r&t          j        t          d          ||fz            |sdg}n1|D ].}||k    r&t          j        t          d          ||fz            /|dz  }|dz
  }	t          |          dk    r(|d         dk    r|r|r	d|z  V  d}rd	V  d
V  d}	nd}t          |          dk    r|d         |	k    rrdV  |dz  }|r	d|z  V  d}rd	V  g }
|D ]Y}||	k    r|
                    d           || v r|
                    | |                    >|
                    d||z
  z             Zdd                    |
          z   V  q|r	d|z  V  d}|dk    r|\  }}|| |<   d|z   V  rd	V  |dk    rd |          z   V  rd	V  |dk    rd|z   V  d	V  |dk    rrd	V  d |          z   V  |dk    rd|z   V  d	V  t          j        t          d          t          j        |          t          j        |          fz            |r	d|z  V  d S d S )Nr   Fr,   s   expected id %i, got %ir	   s)   parent id %i is larger than current id %ir   s   +%d   
r<   Tr+   r   s   %dr.   r/   r5   r4   r:   r8   r9   s   !!r7   r6   r;   s'   invalid event type in dag: ('%s', '%s'))r   rC   r   lenrB   joinr   	escapestr)r   runwantrneedrootkinddatar   rJ   pr   rI   ridrK   eventsusedotswrapannotationswrapcommands
wraplabelswrapnonlinearrU   s                r   genzdagtextlines.<locals>.gen2  s       U	 U	JD$t||2 ::+a(A&B&BeQZ&OPPP BB  66"'+ !%5!" !" $%a&	!)# #  " 
 Ur77a<<BqERKK 	( $"(3,..."#C( ("'KKK"


#'r77a<<BqERKK !"



q  $sl***$ $#E : :77!LL----&[[!LL3333!LL!a%99995!1!111111  3,&&&C4<< $IC"&F3K+%%%! $#T\\D!1!11111# $#T\\$,&&&KKKKT\\& $#D!1!111111T\\+%%%KKKK+DEE&066&066    	3,	 	r   r   rW   r+       N)rX   )rb   	addspacesrf   rd   re   rg   rc   maxlinewidthrh   linepartrU   s   ` `````    @r   dagtextlinesrn   !  s     O O O
\ \ \ \ \ \ \ \ \ \ \| D  5== 


4yy3t99$44


 t DLDD 




 r   c                 T    d                     t          | |||||||                    S )a  generates lines of a textual representation for a dag event stream

    events should generate what parsedag() does, so:

      ('n', (id, [parentids])) for node creation
      ('l', (id, labelname)) for labels on nodes
      ('a', text) for annotations
      ('c', text) for commands
      ('C', text) for line commands ('!!')
      ('#', text) for comment lines

    Parent nodes must come before child nodes.

    Examples
    --------

    Linear run:

        >>> dagtext([(b'n', (0, [-1])), (b'n', (1, [0]))])
        '+2'

    Two roots:

        >>> dagtext([(b'n', (0, [-1])), (b'n', (1, [-1]))])
        '+1 $ +1'

    Fork and join:

        >>> dagtext([(b'n', (0, [-1])), (b'n', (1, [0])), (b'n', (2, [0])),
        ...          (b'n', (3, [2, 1]))])
        '+2 *2 */2'

    Fork and join with labels:

        >>> dagtext([(b'n', (0, [-1])), (b'l', (0, b'f')), (b'n', (1, [0])),
        ...          (b'l', (1, b'p2')), (b'n', (2, [0])), (b'n', (3, [2, 1]))])
        '+1 :f +1 :p2 *f */p2'

    Annotations:

        >>> dagtext([(b'n', (0, [-1])), (b'a', b'ann'), (b'n', (1, [0]))])
        '+1 @ann +1'

        >>> dagtext([(b'n', (0, [-1])),
        ...          (b'a', b'my annotation'),
        ...          (b'n', (1, [0]))])
        '+1 @"my annotation" +1'

    Commands:

        >>> dagtext([(b'n', (0, [-1])), (b'c', b'cmd'), (b'n', (1, [0]))])
        '+1 !cmd +1'

        >>> dagtext([(b'n', (0, [-1])),
        ...          (b'c', b'my command'),
        ...          (b'n', (1, [0]))])
        '+1 !"my command" +1'

        >>> dagtext([(b'n', (0, [-1])),
        ...          (b'C', b'my command line'),
        ...          (b'n', (1, [0]))])
        '+1 !!my command line\n+1'

    Comments:

        >>> dagtext([(b'n', (0, [-1])), (b'#', b' comment'), (b'n', (1, [0]))])
        '+1 # comment\n+1'

        >>> dagtext([])
        ''

    Combining parsedag and dagtext:

        >>> dagtext(parsedag(b'+1 :f +1 :p2 *f */p2'))
        '+1 :f +1 :p2 *f */p2'

    rW   )rY   rn   )dagrj   rf   rd   re   rg   rc   rk   s           r   dagtextrq     s@    n ::		
 		
  r   )TFFFFFrO   )rR   r   i18nr    r   r   utilsr   rN   rn   rq   r   r   r   <module>ru      s    
			                    J J J^ } } } }D b b b b b br   