o
    NEgm                     @   s   d Z ddlZddlZddlmZmZmZmZmZm	Z	 ddl
Z
ddlmZmZ ddlmZ dedee fd	d
Ze
jddG dd dZe
jddG dd dZe
jddG dd deZG dd dZdS )z"Statement parsing classes for cmd2    N)DictIterableListOptionalTupleUnion   )	constantsutils)Cmd2ShlexErrorstr_to_splitreturnc                 C   s   t j| dddS )z
    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    r   f/var/www/eduai.edurigo.com/doc_train/edurigo_ai/Puru/venv/lib/python3.10/site-packages/cmd2/parsing.pyshlex_split   s   r   T)frozenc                   @   sj   e Zd ZdZejejedZ	ejeje
dZejejedZedZedZedZdS )MacroArgz
    Information used to replace or unescape arguments in a macro value when the macro is resolved
    Normal argument syntax:    {5}
    Escaped argument syntax:  {{5}}
    	validatorz(?<!{){\d+}|{\d+}(?!})z{{2}\d+}{2}z\d+N)__name__
__module____qualname____doc__attrib
validatorsinstance_ofintstart_indexstr
number_strbool
is_escapedrecompilemacro_normal_arg_patternmacro_escaped_arg_patterndigit_patternr   r   r   r   r   &   s    

r   c                   @   sh   e Zd ZdZejejedZ	ejejedZ
ejejedZejeeejedZdS )MacrozDefines a cmd2 macror   defaultr   N)r   r   r   r   r   r   r   r    r#   namevaluer!   minimum_arg_countFactorylistarg_listr   r   r   r   r,   F   s     r,   c                       sT  e Zd ZdZejdejedZ	ejdejedZ
ejdejedZejeeejedZejdejedZejdejedZejdejedZejdejedZejdejedZejdejedZdef fddZedefdd	Zedefd
dZedefddZedee fddZ  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
    :meth:`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
       (:func:`~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
       :attr:`~cmd2.Statement.args` or :attr:`~cmd2.Statement.arg_list`

    3. If you don't want to have to worry about quoted arguments, see
       :attr:`argv` for a trick which strips quotes off for you.
     r-   r0   c                    s   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:  attrs takes care of initializing other members in the __init__ it
        generates.
        )super__new__)clsr0   pos_argskw_argsstmt	__class__r   r   r8      s   	zStatement.__new__r   c                 C   s8   | j r| jrd| j | j}|S | j r| j }|S 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.
        z{} {}r6   )commandargsformatselfrtnr   r   r   command_and_args   s   zStatement.command_and_argsc                 C   sh   d}| j r
|| j 7 }| jr|d| j 7 }| jr|d| j 7 }| jr2|d| j 7 }| jr2|d| j 7 }|S )zHA string containing any ending terminator, suffix, and redirection charsr6    z | )
terminatorsuffixpipe_tooutput	output_torB   r   r   r   post_command   s   
zStatement.post_commandc                 C   s   | j | j S )zeConcatenate :meth:`~cmd2.Statement.command_and_args`
        and :meth:`~cmd2.Statement.post_command`)rE   rL   )rC   r   r   r   expanded_command_line   s   zStatement.expanded_command_linec                 C   s<   | j rt| j g}| jD ]
}|t| q|S 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:]``.
        )r?   r
   strip_quotesr4   append)rC   rD   	cur_tokenr   r   r   argv   s   
zStatement.argv)r   r   r   r   r   r   r   r    r#   r@   rawr?   r2   r3   r4   multiline_commandrG   rH   rI   rJ   rK   objectr8   propertyrE   rL   rM   r   rQ   __classcell__r   r   r=   r   r5   W   s*    r5   c                   @   s:  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d	Zd
ddede	de
e	ef fddZdedee fddZdedefddZdedefddZdedeeef de	de
eee f fddZdedefddZedee de
eef fd d!Zdee dee fd"d#ZdS )%StatementParserz>Parse user input as a string into discrete command components.Nterminatorsmultiline_commandsaliases	shortcutsr   c           	      C   s   |du r
t jf| _nt|| _|du rt | _nt|| _|du r&t | _n|| _|du r0t j}tt|	 dd dd| _
g }|t j |t j || j dd |D }|dd	g d
|}d|}t|| _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
        Nc                 S   s   t | d S )Nr   )len)xr   r   r   <lambda>  s    z*StatementParser.__init__.<locals>.<lambda>T)keyreversec                 S      g | ]}t |qS r   )r'   escape.0r]   r   r   r   
<listcomp>      z,StatementParser.__init__.<locals>.<listcomp>z\sz\Z|z\A\s*(\S*?)({}))r	   MULTILINE_TERMINATORrX   tuplerY   dictrZ   DEFAULT_SHORTCUTSsorteditemsr[   extendQUOTESREDIRECTION_CHARSjoinrA   r'   r(   _command_pattern)	rC   rX   rY   rZ   r[   invalid_command_charssecond_group_itemssecond_groupexprr   r   r   __init__   s*   





zStatementParser.__init__F)is_subcommandwordrx   c          	      C   s   d}t |tsddtt|fS |sdS |tjrdS |sB| jD ]\}}||rAd}|ddd | jD 7 }d|f  S q#d	}g }|	tj
 |	| j |dd
d |D 7 }| j|}|rq||dkrqd}d}||fS )a  Determine whether a word is a valid name for a command.

        Commands can not 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 = "alias: {}".format(errmsg)
        Fz%must be a string. Received {} instead)Fzcannot be an empty string)Fz'cannot start with the comment characterzcannot start with a shortcut: z, c                 s   s    | ]\}}|V  qd S )Nr   )rd   shortcut_r   r   r   	<genexpr>F  s    z3StatementParser.is_valid_command.<locals>.<genexpr>z$cannot contain: whitespace, quotes, c                 S   ra   r   )r   quoterc   r   r   r   re   M  rf   z4StatementParser.is_valid_command.<locals>.<listcomp>r   Tr6   )
isinstancer#   rA   type
startswithr	   COMMENT_CHARr[   rq   rn   rp   rX   rr   searchgroup)	rC   ry   rx   validrz   r{   errmsgerrcharsmatchr   r   r   is_valid_command#  s2   

z StatementParser.is_valid_commandlinec              
   C   sZ   |  |}| tjrg S zt|}W n ty% } zt|d}~w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)rC   r   tokensexr   r   r   tokenizeV  s   

zStatementParser.tokenizec                 C   s  d}|dd t jkrt j}d}d}g }| |}t|d }t|D ]\}}	| jD ]}
|	|
r7|}|
} nq*q# |ra|t jkrGt|d }| |d| \}}|d| }||d d }n| |\}}|| jv ry|}|}|dd }g }d}d}d}z|	t j
}W n ty   t|}Y nw z|	t j}W n ty   t|}Y nw z|	t j}W n ty   t|}Y nw ||k r||k r||d d }t| d|}|d| }n8||kr||k rt j}|}nt j}|}t||d krt||d  }|rt||d  }|d| }|r#d|}nd}|s5| |\}}|dd }|| jv r>|}nd}t||||||||||d
}|S )a  
        Tokenize the input and parse it into a :class:`~cmd2.Statement` object,
        stripping comments, expanding aliases and shortcuts, and extracting output
        redirection directives.

        :param line: the command line being parsed
        :return: a new :class:`~cmd2.Statement` object
        :raises: Cmd2ShlexError if a shlex error occurs (e.g. No closing quotation)
        r6   Nr   rF   )	rR   r?   r4   rS   rG   rH   rI   rJ   rK   )r	   	LINE_FEEDr   r\   	enumeraterX   r   _command_and_argsrY   indexREDIRECTION_PIPEr   REDIRECTION_OUTPUTREDIRECTION_APPENDr
   expand_user_in_tokensrq   rN   expand_userr5   )rC   r   rG   r?   r@   r4   r   terminator_posposrP   test_terminatortestcommandtestargsrI   rJ   rK   
pipe_indexredir_indexappend_indexpipe_to_tokensoutput_indexunquoted_pathrH   rS   	statementr   r   r   parseq  s   









zStatementParser.parserawinputc                 C   sv   |  |}d}d}| j|}|r'|d}||dd  }|r%|s'd}|| jv r/|}nd}t||||d}|S )ah  Partially parse input into a :class:`~cmd2.Statement` object.

        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 :class:`~cmd2.Statement` object returned by this method can at most
        contain values in the following attributes:
        :attr:`~cmd2.Statement.args`, :attr:`~cmd2.Statement.raw`,
        :attr:`~cmd2.Statement.command`,
        :attr:`~cmd2.Statement.multiline_command`

        :attr:`~cmd2.Statement.args` will include all output redirection
        clauses and command terminators.

        Different from :meth:`~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 :class:`~cmd2.Statement` object
        r6   r   N)rR   r?   rS   )r   rr   r   r   endstriprY   r5   )rC   r   r   r?   r@   r   rS   r   r   r   r   parse_command_only  s$   


z"StatementParser.parse_command_onlycommand_nameto_parsepreserve_quotesc                 C   s<   t |ts| |d | }|r||jfS ||jdd fS )af  
        Convenience method used by the argument parsing decorators.

        Retrieves just the arguments being passed to their ``do_*`` methods as a list.

        :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 :class:`~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
                                :class:`~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 :class:`~cmd2.Statement` and a list of
                 strings representing the arguments
        rF   r   N)r~   r5   r   r4   rQ   )rC   r   r   r   r   r   r   get_command_arg_list=  s
   

z$StatementParser.get_command_arg_listc           	      C   s   t | j }t|}|r>d}| j|}|r<|d}||v r<| j| |d ||dd  }|| t|}|s| j	D ]'\}}|
|rht|}t||ksZ|| dkr^|d7 }|||d} |S qA|S )zExpand aliases and shortcutsFr      NrF   )r3   rZ   keysr%   rr   r   r   r   remover[   r   r\   replace)	rC   r   remaining_aliaseskeep_expandingr   r?   rz   	expansionshortcut_lenr   r   r   r   ^  s,   
&

	zStatementParser._expandr   c                 C   s:   d}d}| r
| d }t | dkrd| dd }||fS )z`Given a list of tokens, return a tuple of the command
        and the args as a string.
        r6   r   r   rF   N)r\   rq   )r   r?   r@   r   r   r   r     s   z!StatementParser._command_and_argsc           	      C   s  g }| | j | tj g }|D ]l}t|dks!|d tjv r'|| qd}|| }d}	 ||vrQ||vrP||7 }|d7 }|t|k rK|| }nn||vs8n|}||kro||7 }|d7 }|t|k rj|| }nn||ksW|| d}|t|kr}nq0q|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   )rn   rX   r	   rp   r\   ro   rO   )	rC   r   punctuationpunctuated_tokenscur_initial_token	cur_indexcur_char	new_tokencur_puncr   r   r   r     sH   


	

	z$StatementParser.split_on_punctuation)NNNN)r   r   r   r   r   r   r#   r   rw   r%   r   r   r   r   r5   r   r   r   r   r   staticmethodr   r   r   r   r   r   rW      s>    


$C3 ;
!$ rW   )r   r'   r   typingr   r   r   r   r   r   r   r6   r	   r
   
exceptionsr   r#   r   sr   r,   r5   rW   r   r   r   r   <module>   s     	


 