
    |im                     X   d Z 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	m
Z
mZ ddlmZmZ ddlmZ d	ed
ee         fdZ ed           G d d                      Z ed           G d d                      Z ed           G d de                      Z G d d          ZdS )z#Statement parsing classes for cmd2.    N)Iterable)	dataclassfield)AnyOptionalUnion   )	constantsutils)Cmd2ShlexErrorstr_to_splitreturnc                 0    t          j        | dd          S )a/  Split the string *str_to_split* using shell-like syntax.

    A wrapper around shlex.split() that uses cmd2's preferred arguments.

    This allows other classes to easily call split() the same way StatementParser does.

    :param str_to_split: the string being split
    :return: A list of tokens
    F)commentsposix)shlexsplit)r   s    \/home/jenkins/workspace/simtester-sanitize/venv/lib/python3.11/site-packages/cmd2/parsing.pyshlex_splitr      s     ;|e5AAAA    T)frozenc                       e Zd ZU dZeed<   eed<   eed<    ej	        d          Z
 ej	        d          Z ej	        d          ZdS )	MacroArgzInformation used to replace or unescape arguments in a macro value when the macro is resolved.

    Normal argument syntax:    {5}
    Escaped argument syntax:  {{5}}.
    start_index
number_str
is_escapedz(?<!{){\d+}|{\d+}(?!})z{{2}\d+}{2}z\d+N)__name__
__module____qualname____doc__int__annotations__strboolrecompilemacro_normal_arg_patternmacro_escaped_arg_patterndigit_pattern r   r   r   r   &   s}           
 OOO 
  *rz*CDD
 !+
> : : BJv&&MMMr   r   c                   `    e Zd ZU dZeed<   eed<   eed<    ee          Z	ee
         ed<   dS )MacrozDefines a cmd2 macro.namevalueminimum_arg_countdefault_factoryarg_listN)r   r   r   r    r#   r"   r!   r   listr2   r   r*   r   r   r,   r,   G   s_          III JJJ   %uT:::Hd8n:::::r   r,   c                       e Zd ZU dZdZeed<   dZeed<   dZeed<    e	e
          Ze
e         ed<   dZeed<   dZeed	<   dZeed
<   dZeed<   dZeed<   dZeed<   dZdedededd f fdZedefd            Zedefd            Zedefd            Zede
e         fd            Zdeeef         fdZedeeef         dd fd            Z xZS )	Statementa;  String subclass with additional attributes to store the results of parsing.

    The ``cmd`` module in the standard library passes commands around as a
    string. To retain backwards compatibility, ``cmd2`` does the same. However,
    we need a place to capture the additional output of the command parsing, so
    we add our own attributes to this subclass.

    Instances of this class should not be created by anything other than the
    [StatementParser.parse][cmd2.parsing.StatementParser.parse] method, nor should any of the
    attributes be modified once the object is created.

    The string portion of the class contains the arguments, but not the
    command, nor the output redirection clauses.

    Tips:

    1. `argparse <https://docs.python.org/3/library/argparse.html>`_ is your
       friend for anything complex. ``cmd2`` has the decorator
       ([cmd2.decorators.with_argparser][]) which you can
       use to make your command method receive a namespace of parsed arguments,
       whether positional or denoted with switches.

    2. For commands with simple positional arguments, use
       [args][cmd2.Statement.args] or [arg_list][cmd2.Statement.arg_list]

    3. If you don't want to have to worry about quoted arguments, see
       [argv][cmd2.Statement.argv] for a trick which strips quotes off for you.
     argsrawcommandr0   r2   multiline_command
terminatorsuffixpipe_tooutput	output_tor.   	_pos_args_kw_argsr   c                 H    t                                          | |          S )a,  Create a new instance of Statement.

        We must override __new__ because we are subclassing `str` which is
        immutable and takes a different number of arguments as Statement.

        NOTE:  @dataclass takes care of initializing other members in the __init__ it
        generates.
        )super__new__)clsr.   r@   rA   	__class__s       r   rD   zStatement.__new__   s     wwsE***r   c                 h    | j         r| j        r| j          d| j         }n| j         r| j         }nd}|S )zCombine command and args with a space separating them.

        Quoted arguments remain quoted. Output redirection and piping are
        excluded, as are any command terminators.
         r6   )r9   r7   selfrtns     r   command_and_argszStatement.command_and_args   sM     < 	DI 	\//DI//CC\ 	,CCC
r   c                     d}| j         r
|| j         z  }| j        r|d| j        z   z  }| j        r|d| j        z   z  }| j        r!|d| j        z   z  }| j        r|d| j        z   z  }|S )zIA string containing any ending terminator, suffix, and redirection chars.r6   rH   z | )r;   r<   r=   r>   r?   rI   s     r   post_commandzStatement.post_command   s     ? 	#4?"C; 	%3$$C< 	(54<''C; 	,3$$C~ ,sT^++
r   c                      | j         | j        z   S )zpConcatenate [command_and_args][cmd2.Statement.command_and_args] and [post_command][cmd2.Statement.post_command].)rL   rN   rJ   s    r   expanded_command_linezStatement.expanded_command_line   s     $t'888r   c                     | j         r?t          j        | j                   g}|                    d | j        D                        ng }|S )a  A list of arguments a-la ``sys.argv``.

        The first element of the list is the command after shortcut and macro
        expansion. Subsequent elements of the list contain any additional
        arguments, with quotes removed, just like bash would. This is very
        useful if you are going to use ``argparse.parse_args()``.

        If you want to strip quotes from the input, you can use ``argv[1:]``.
        c              3   >   K   | ]}t          j        |          V  d S N)r   strip_quotes).0	cur_tokens     r   	<genexpr>z!Statement.argv.<locals>.<genexpr>   s-      TTu))44TTTTTTr   )r9   r   rU   extendr2   rI   s     r   argvzStatement.argv   sS     < 	%dl334CJJTTdmTTTTTTTC
r   c                 4    | j                                         S )zRConvert this Statement into a dictionary for use in persistent JSON history files.)__dict__copyrP   s    r   to_dictzStatement.to_dict   s    }!!###r   source_dictc                     	 | t           j                 }n&# t          $ r}t          d| d          dd}~ww xY w|                                 }|t           j        = t          |fi |S )zRestore a Statement from a dictionary.

        :param source_dict: source data dictionary (generated using to_dict())
        :return: Statement object
        :raises KeyError: if source_dict is missing required elements
        z Statement dictionary is missing z fieldN)r5   _args_fieldKeyErrorr]   )r_   r.   exkwargss       r   	from_dictzStatement.from_dict   s    	T	 56EE 	T 	T 	THbHHHIItS	T !!##9()))&)))s    
838) r   r   r   r    r7   r#   r"   r8   r9   r   r3   r2   r:   r;   r<   r=   r>   r?   ra   objectr   rD   propertyrL   rN   rQ   rZ   dictr^   staticmethodre   __classcell__)rF   s   @r   r5   r5   X   s%         < D#NNN CMMM GS  %555Hd3i555  s J FC GS FC Is K	+F 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ #    X c    X& 9s 9 9 9 X9 d3i    X$$c3h $ $ $ $ *tCH~ *+ * * * \* * * * *r   r5   c                      e Zd ZdZ	 	 	 	 ddeee                  deee                  deeeef                  deeeef                  ddf
dZd	d
dede	de
e	ef         fdZdedee         fdZdedefdZdedefdZdedeeef         de	de
eee         f         fdZdedefdZedee         de
eef         fd            Zdee         dee         fdZdS )StatementParserz>Parse user input as a string into discrete command components.Nterminatorsmultiline_commandsaliases	shortcutsr   c                    |  |t           j        f| _        nt          |          | _        |t          |          nd| _        ||ni | _        |t           j        }t          t          |                                d d                    | _	        g }|
                    t           j                   |
                    t           j                   |
                    | j                   d |D             }|
                    ddg           d	                    |          }d
| d}t          j        |          | _        dS )a  Initialize an instance of StatementParser.

        The following will get converted to an immutable tuple before storing internally:
        terminators, multiline commands, and shortcuts.

        :param terminators: iterable containing strings which should terminate commands
        :param multiline_commands: iterable containing the names of commands that accept multiline input
        :param aliases: dictionary containing aliases
        :param shortcuts: dictionary containing shortcuts
        Nr*   c                 ,    t          | d                   S )Nr   )len)xs    r   <lambda>z*StatementParser.__init__.<locals>.<lambda>  s    s1Q4yy r   T)keyreversec                 6    g | ]}t          j        |          S r*   )r%   escaperV   rt   s     r   
<listcomp>z,StatementParser.__init__.<locals>.<listcomp>1  s     JJJqbillJJJr   z\sz\Z|z\A\s*(\S*?)())r
   MULTILINE_TERMINATORrm   tuplern   ro   DEFAULT_SHORTCUTSsorteditemsrp   rY   QUOTESREDIRECTION_CHARSjoinr%   r&   _command_pattern)	rJ   rm   rn   ro   rp   invalid_command_charssecond_group_itemssecond_groupexprs	            r   __init__zStatementParser.__init__   sP   " 	) ) >@D$[11DPbPn59K3L3L3Ltv292Eww2!3I vioo&7&7=P=PZ^___``& !#$$Y%5666$$Y%@AAA$$T%5666JJ4IJJJ 	!!5%.111xx 233.|... "
4 0 0r   F)is_subcommandwordr   c                   d}t          |t                    sddt          |          dfS |sdS |                    t          j                  rdS |sQ| j        D ]I\  }}|                    |          r/d}|d                    d | j        D                       z  }d|fc S Jd	}g }|                    t          j	                   |                    | j
                   |d                    d
 |D                       z  }| j                            |          }|r||                    d          k    rd}d}||fS )a  Determine whether a word is a valid name for a command.

        Commands cannot include redirection characters, whitespace,
        or termination characters. They also cannot start with a
        shortcut.

        :param word: the word to check as a command
        :param is_subcommand: Flag whether this command name is a subcommand name
        :return: a tuple of a boolean and an error string

        If word is not a valid command, return ``False`` and an error string
        suitable for inclusion in an error message of your choice::

            checkit = '>'
            valid, errmsg = statement_parser.is_valid_command(checkit)
            if not valid:
                errmsg = f"alias: {errmsg}"
        Fzmust be a string. Received z instead)Fzcannot be an empty string)Fz'cannot start with the comment characterzcannot start with a shortcut: z, c              3       K   | ]	\  }}|V  
d S rT   r*   )rV   shortcut_s      r   rX   z3StatementParser.is_valid_command.<locals>.<genexpr>^  s&      'U'U]h'U'U'U'U'U'Ur   z$cannot contain: whitespace, quotes, c                 6    g | ]}t          j        |          S r*   )r   quoterz   s     r   r{   z4StatementParser.is_valid_command.<locals>.<listcomp>e  s     >>>U[^^>>>r   r	   Tr6   )
isinstancer#   type
startswithr
   COMMENT_CHARrp   r   rY   r   rm   r   searchgroup)	rJ   r   r   validr   r   errmsgerrcharsmatchs	            r   is_valid_commandz StatementParser.is_valid_command;  sx   & $$$ 	ONT

NNNNN 	655??9122 	DCC 	)#~ ) )!??8,, )=Fdii'U'Udn'U'U'UUUUF &=(((	) 8	3444()))$))>>X>>>???%,,T22 	TU[[^^++EFf}r   linec                 "   |                      |          }|                                                    t          j                  rg S 	 t          |          }n"# t          $ r}t          |          dd}~ww xY w|                     |          S )a  Lex a string into a list of tokens. Shortcuts and aliases are expanded and comments are removed.

        :param line: the command line being lexed
        :return: A list of tokens
        :raises Cmd2ShlexError: if a shlex error occurs (e.g. No closing quotation)
        N)	_expandlstripr   r
   r   r   
ValueErrorr   split_on_punctuation)rJ   r   tokensrc   s       r   tokenizezStatementParser.tokenizem  s     ||D!! ;;==##I$:;; 	I	/ &&FF 	/ 	/ 	/ $$$.	/ ((000s   
A 
A9$A44A9c                 0   d}|dd         t           j        k    rt           j        }d}d}g }|                     |          }t          |          dz   }t	          |          D ]+\  }}	| j        D ]}
|	                    |
          r|}|
} n+ |rZ|t           j        k    rt          |          dz   }|                     |d|                   \  }}|d|         }||dz   d         }n1|                     |          \  }}|| j        v r|}|}|dd         }g }d}d}d}	 |	                    t           j
                  }n# t          $ r t          |          }Y nw xY w	 |	                    t           j                  }n# t          $ r t          |          }Y nw xY w	 |	                    t           j                  }n# t          $ r t          |          }Y nw xY w||k     rG||k     rA||dz   d         }t          j        |           d                    |          }|d|         }n||k    r||k     rt           j        }|}nt           j        }|}t          |          |dz   k    r<t          j        ||dz                      }|rt          j        ||dz                      }|d|         }|rd                    |          }n&d}|s"|                     |          \  }}|dd         }|| j        v r|nd}t'          ||||||||||
  
        S )a  Tokenize the input and parse it into a [cmd2.parsing.Statement][] object.

        Stripping comments, expanding aliases and shortcuts, and extracting output redirection directives.

        :param line: the command line being parsed
        :return: a new [cmd2.parsing.Statement][] object
        :raises Cmd2ShlexError: if a shlex error occurs (e.g. No closing quotation)
        r6   Nr	   rH   )	r8   r9   r2   r:   r;   r<   r=   r>   r?   )r
   	LINE_FEEDr   rs   	enumeraterm   r   _command_and_argsrn   indexREDIRECTION_PIPEr   REDIRECTION_OUTPUTREDIRECTION_APPENDr   expand_user_in_tokensr   rU   expand_userr5   )rJ   r   r;   r9   r7   r2   r   terminator_posposrW   test_terminatortestcommandtestargsr=   r>   r?   
pipe_indexredir_indexappend_indexpipe_to_tokensoutput_indexunquoted_pathr<   r:   s                           r   parsezStatementParser.parse  s    
9	+++",J t$$ Vq'// 	 	NC#'#3  ''88 %(N!0J E  	Y000!$Vq #44VO^O5LMMOWda./H NQ.001FF&*&<&<V&D&D#[(d555 &!!"":		%i&@AAJJ 	% 	% 	%VJJJ	%	& ,,y'CDDKK 	& 	& 	&f++KKK	&	'!<<	(DEELL 	' 	' 	'v;;LLL	' ##
\(A(A#JN$4$45N'777 hh~..G KZK(FF L((\))"5*"5+ 6{{\A--- % 26,:J3K L L  L % 1&9I2J K KI M\M*F 		&XXf%%FF F &"&"8"8"@"@$!!"": (/$2I'I'IGGr /!
 
 
 	
s6   #E EE#F FF#G GGrawinputc                    |                      |          }d}d}| j                            |          }|r|                    d          }||                    d          d                                         }	 t          |           |                                }n# t          $ r Y nw xY w|r|sd}|| j	        v r|nd}t          ||||          S )aj  Parse input into a [cmd2.Statement][] object (partially).

        The command is identified, and shortcuts and aliases are expanded.
        Multiline commands are identified, but terminators and output
        redirection are not parsed.

        This method is used by tab completion code and therefore must not
        generate an exception if there are unclosed quotes.

        The [cmd2.parsing.Statement][] object returned by this method can at most
        contain values in the following attributes:
        [cmd2.parsing.Statement.args][], [cmd2.parsing.Statement.raw][],
        [cmd2.parsing.Statement.command][],
        [cmd2.parsing.Statement.multiline_command][]

        [cmd2.parsing.Statement.args][] will include all output redirection
        clauses and command terminators.

        Different from [cmd2.parsing.StatementParser.parse][] this method
        does not remove redundant whitespace within args. However, it does
        ensure args has no leading or trailing whitespace.

        :param rawinput: the command line as entered by the user
        :return: a new [cmd2.Statement][] object
        r6   r	   N)r8   r9   r:   )r   r   r   r   endr   r   rstripr   rn   r5   )rJ   r   r   r9   r7   r   r:   s          r   parse_command_onlyz"StatementParser.parse_command_only  s   6 ||H%%%,,T22 	kk!nnG
 		!'..00D%D!!!
 {{}}	      $  (/$2I'I'IGGr 8WPabbbbs   ;B 
B,+B,command_nameto_parsepreserve_quotesc                     t          |t                    s|                     |dz   |z             }|r	||j        fS ||j        dd         fS )aJ  Retrieve just the arguments being passed to their ``do_*`` methods as a list.

        Convenience method used by the argument parsing decorators.

        :param command_name: name of the command being run
        :param to_parse: what is being passed to the ``do_*`` method. It can be one of two types:

                             1. An already parsed [cmd2.Statement][]
                             2. An argument string in cases where a ``do_*`` method is
                                explicitly called. Calling ``do_help('alias create')`` would
                                cause ``to_parse`` to be 'alias create'.

                                In this case, the string will be converted to a
                                [cmd2.Statement][] and returned along with
                                the argument list.

        :param preserve_quotes: if ``True``, then quotes will not be stripped from
                                the arguments
        :return: A tuple containing the [cmd2.Statement][] and a list of
                 strings representing the arguments
        rH   r	   N)r   r5   r   r2   rZ   )rJ   r   r   r   s       r   get_command_arg_listz$StatementParser.get_command_arg_listK  s^    2 (I.. 	Azz,"4x"?@@H 	/X...qrr***r   c                    t          | j                                                  }t          |          }|rd}| j                            |          }|r~|                    d          }||v re| j        |         |                    d          z   ||                    d          d         z   }|                    |           t          |          }|| j	        D ]h\  }}|
                    |          rNt          |          }|}	t          |          |k    s||         dk    r|	dz  }	|                    ||	d          } ni|S )zExpand aliases and shortcuts.Fr	      NrH   )r3   ro   keysr$   r   r   r   r   removerp   r   rs   replace)
rJ   r   remaining_aliaseskeep_expandingr   r9   r   	expansionshortcut_leneffective_expansions
             r   r   zStatementParser._expandk  si    !!2!2!4!455/00 	="N )0066E 	=++a.. ///<05;;q>>ADSTDXXD%,,W555%)*;%<%<N  	=" $(> 
	 
	Hix(( 	"8}}&/#t99,,\0Bc0I0I'3.' ||H.A1EE	 r   r   c                     d}d}| r| d         }t          |           dk    rd                    | dd                   }||fS )zOGiven a list of tokens, return a tuple of the command and the args as a string.r6   r   r	   rH   N)rs   r   )r   r9   r7   s      r   r   z!StatementParser._command_and_args  sQ      	 QiGv;;??88F122J''D}r   c                 H   g }|                     | j                   |                     t          j                   g }|D ]}t	          |          dk    s|d         t          j        v r|                    |           ?d}||         }d}	 ||vr0||vr+||z  }|dz  }|t	          |          k     r	||         }nn||v+n5|}||k    r-||z  }|dz  }|t	          |          k     r	||         }nn||k    -|                    |           d}|t	          |          k    rn|S )a|  Further splits tokens from a command line using punctuation characters.

        Punctuation characters are treated as word breaks when they are in
        unquoted strings. Each run of punctuation characters is treated as a
        single token.

        :param tokens: the tokens as parsed by shlex
        :return: a new list of tokens, further split using punctuation
        r	   r   r6   )rY   rm   r
   r   rs   r   append)	rJ   r   punctuationpunctuated_tokenscur_initial_token	cur_indexcur_char	new_tokencur_puncs	            r   r   z$StatementParser.split_on_punctuation  s    "$4+,,,96777!' *	 *	$%%**.?.BiFV.V.V!(():;;; I(3H I;.."+55!X-	!Q	$s+<'='==='8'CHH! #+55  (H #h..!X-	!Q	$s+<'='==='8'CHH! #h.. "((333	 $5 6 666;:   r   )NNNN)r   r   r   r    r   r   r#   rh   r   r$   r   r   r3   r   r5   r   r   r   r   r   ri   r   r   r*   r   r   rl   rl      s0       HH 046:,0.2>1 >1hsm,>1 %Xc]3>1 $sCx.)	>1
 DcN+>1 
>1 >1 >1 >1@ DI 0 0 0S 0D 0USWY\S\M] 0 0 0 0d1S 1T#Y 1 1 1 1.J
# J
) J
 J
 J
 J
X9c3 9c9 9c 9c 9c 9cv+++0C+@+SW+	y$s)#	$+ + + +@"C "C " " " "H $s) c3h    \<!49 <!c <! <! <! <! <! <!r   rl   )r    r%   r   collections.abcr   dataclassesr   r   typingr   r   r   r6   r
   r   
exceptionsr   r#   r3   r   r   r,   r5   rl   r*   r   r   <module>r      s	   ) ) 				  $ $ $ $ $ $                            

Bc 
Bd3i 
B 
B 
B 
B $' ' ' ' ' ' ' '@ $; ; ; ; ; ; ; ;  $\* \* \* \* \* \* \* \*~a! a! a! a! a! a! a! a! a! a!r   