Home > OS >  How to generate a syntax string from a list of argument formats
How to generate a syntax string from a list of argument formats

Time:04-21

I don't know exactly how to phrase the title, so I'll explain here:

I have a custom command parser for a chat room bot that parses arguments using this structure (example):

anal_format = [
    {'user': str, 'required_pokes': str | list, 'depth': int, 'format': str},
    {'user': str, 'required_pokes': str | list, 'depth': int},
    {'user': str, 'required_pokes': str | list},
    {'user': str, 'depth': int, 'required_pokes': str | list},
    {'user': str, 'depth': int},
    {'user': str},
]

It loops over every format dict and checks if the passed arguments match, priority is given to the top dict, and so on.

I want to generate a syntax string that looks like this:

'anal <user> [<required_pokes> [<depth> [<format>]]] || anal <user> [<depth> [<required_pokes>]]'

Arguments in square brackets are optional and require the arguments outside of them. So in this case, you would need to specify 'user' before any other arguments.

How would one go about doing this?

CodePudding user response:

Here is way to handle this.

anal_format = [
{'user': 'Test1', 'required_pokes': ['List1', 'List2'], 'depth': 1, 'format': 'A format'},
{'user': 'Test2', 'required_pokes': ['List1', 'List2'], 'depth': 2},
{'user': 'Test3', 'required_pokes': ['List1', 'List2']},
{'user': 'Test4', 'depth': 3, 'required_pokes': ['List1', 'List2']},
{'user': 'Test5', 'depth': 4},
{'user': 'Test6'}]

new_string = ''

for user in anal_format:
if new_string != '':
    new_string  = ' || '
new_string  = f"anal {user['user']}"
needed_brackets = ''
if 'required_pokes' in user:
    new_string  = f" [{(','.join(user['required_pokes']))}"
    needed_brackets  = ']'
if 'depth' in user:
    new_string  = f" [{user['depth']}"
    needed_brackets  = ']'
if 'format' in user:
    new_string  = f" [{user['format']}"
    needed_brackets  = ']'
new_string  = needed_brackets


print(new_string)

Let me know if that's what you were thinking.

CodePudding user response:

I ended up changing the command format structure to something that resembles this:

format = [
    {'args': {'user': str}, 'optional': {
        'args': {'required_pokes': str | list},
        'optional': {
            'args': {'depth': int},
            'optional': {
                'args': {'format': str}
               }
            },
        }
    },
    {'args': {'user': str}, 'optional': {
        'args': {'depth': int},
        'optional': {
            'args': {'required_pokes': str | list}
           }
        }
    }
]

This makes it much easier to work with. Here's the code that generates the strings:

...
def syntax_string(syntax):
    sl = [f'<{s}>' for s in syntax if isinstance(s, str)]
    string = ' '.join(sl)
    if len(syntax) > len(sl):
        string  = ' ['
        string  = syntax_string(syntax[-1])
        string  = ']'
    return string
...
def generate_syntax_strings(formats: list, cmd: str) -> str:
    pre = []
    for f in formats:
        current = [*f['args'].keys()]
        f = f.get('optional')
        i = 0
        while f is not None:
            insert_into_deepest_list(current, [*f['args'].keys()])
            f = f.get('optional')
            i  = 1
        pre.append((current, i))
    return ' || '.join([cmd   ' '   syntax_string(p) for p in pre])

Here's the new parsing function:

def advanced_split_command(cmd: str, fs: list, fallback: dict = None, token_parser: callable = None):
    if fallback is None:
        fallback = dict()
    final = fallback
    s = cmd.split(' ')
    args = ' '.join(s[1:]).split(', ')

    if token_parser is None:
        args = [
            int(token) if token.isnumeric() else
            token.split(';') if ';' in token
            else token
            for token in args
        ]
    else:
        args = [
            token_parser(token, n, len(args))
            for n, token in enumerate(args)
        ]

    for f in fs:
        fk = [*f['args'].keys()]
        ft = [*f['args'].values()]
        f = f.get('optional')
        while f is not None:
            fk  = [*f['args'].keys()]
            ft  = [*f['args'].values()]
            f = f.get('optional')
        if better_match_case(args, ft):
            final = dict(zip(fk, args))
            break

    return s[0], final

The updated code will be on yoursred/showdown-anal-bot

  • Related