def check_function_args(args, signatures, function_name):
messages = []<EOL>arg_types = []<EOL>for arg in args:<EOL><INDENT>arg_type = arg.__class__.__name__<EOL>if arg_type == "<STR_LIT>":<EOL><INDENT>arg_types.append((arg.name, "<STR_LIT>"))<EOL><DEDENT>elif arg_type == "<STR_LIT>":<EOL><INDENT>arg_types.append((arg_type, f"<STR_LIT>"))<EOL><DEDENT>elif arg_type == "<STR_LIT>":<EOL><INDENT>arg_types.append((arg_type, arg.value))<EOL><DEDENT><DEDENT>log.debug(f"<STR_LIT>")<EOL>matched_signature_idx = -<NUM_LIT:1><EOL>valid_function = False<EOL>for sig_argset_idx, sig_argset in enumerate(signatures):<EOL><INDENT>sig_req_args = sig_argset["<STR_LIT>"]  <EOL>sig_pos_args = sig_argset["<STR_LIT>"]  <EOL>sig_opt_args = sig_argset["<STR_LIT>"]  <EOL>sig_mult_args = sig_argset["<STR_LIT>"]  <EOL>log.debug(f"<STR_LIT>")<EOL>log.debug(f"<STR_LIT>")<EOL>log.debug(f"<STR_LIT>")<EOL>log.debug(f"<STR_LIT>")<EOL>reqs_mismatch_flag = False<EOL>for sig_idx, sig_req in enumerate(sig_req_args):<EOL><INDENT>if len(arg_types) > sig_idx:<EOL><INDENT>log.debug(<EOL>"<STR_LIT>".format(<EOL>arg_types[sig_idx][<NUM_LIT:0>], sig_req<EOL>)<EOL>)<EOL>if arg_types[sig_idx][<NUM_LIT:0>] not in sig_req:<EOL><INDENT>reqs_mismatch_flag = True<EOL>msg = f"<STR_LIT>"<EOL>messages.append(msg)<EOL>log.debug(msg)<EOL>break<EOL><DEDENT><DEDENT><DEDENT>if reqs_mismatch_flag:<EOL><INDENT>continue  <EOL><DEDENT>pos_dep_arg_types = arg_types[len(sig_req_args) :]<EOL>log.debug(f"<STR_LIT>")<EOL>log.debug(f"<STR_LIT>")<EOL>pos_mismatch_flag = False<EOL>for sig_pos_idx, sig_pos in enumerate(sig_pos_args):<EOL><INDENT>if sig_pos_idx == len(pos_dep_arg_types):<EOL><INDENT>break  <EOL><DEDENT>if pos_dep_arg_types[sig_pos_idx][<NUM_LIT:0>] not in sig_pos:<EOL><INDENT>pos_mismatch_flag = True<EOL>msg = f"<STR_LIT>"<EOL>messages.append(msg)<EOL>log.debug(msg)<EOL>break<EOL><DEDENT><DEDENT>if pos_mismatch_flag:<EOL><INDENT>continue  <EOL><DEDENT>reqpos_arglen = len(sig_req_args) + len(sig_pos_args)<EOL>optional_arg_types = arg_types[reqpos_arglen:]<EOL>optional_types = [<EOL>(opt_type, opt_val)<EOL>for opt_type, opt_val in optional_arg_types<EOL>if opt_type not in sig_mult_args<EOL>]<EOL>log.debug(f"<STR_LIT>")<EOL>if len(optional_types) != len(set(optional_types)):<EOL><INDENT>msg = f"<STR_LIT>"<EOL>messages.append(msg)<EOL>log.debug(msg)<EOL>continue<EOL><DEDENT>optional_types = [<EOL>(opt_type, opt_val)<EOL>for opt_type, opt_val in optional_types<EOL>if opt_type not in sig_opt_args<EOL>]<EOL>if len(optional_types) > <NUM_LIT:0>:<EOL><INDENT>msg = f"<STR_LIT>"<EOL>messages.append(msg)<EOL>log.debug(msg)<EOL>continue<EOL><DEDENT>matched_signature_idx = sig_argset_idx<EOL>messages = []  <EOL>valid_function = True<EOL>break<EOL><DEDENT>if matched_signature_idx > -<NUM_LIT:1>:<EOL><INDENT>log.debug(<EOL>f'<STR_LIT>'<EOL>)<EOL>for arg_idx, arg in enumerate(args):<EOL><INDENT>log.debug(f"<STR_LIT>")<EOL>for sig_idx, sig_arg in enumerate(<EOL>signatures[matched_signature_idx]["<STR_LIT>"]<EOL>):<EOL><INDENT>if arg.type == "<STR_LIT>" or sig_arg["<STR_LIT:type>"] in [<EOL>"<STR_LIT>",<EOL>"<STR_LIT>",<EOL>]:<EOL><INDENT>pass  <EOL><DEDENT>elif sig_arg.get("<STR_LIT>", None):<EOL><INDENT>if sig_arg["<STR_LIT>"] == arg_idx + <NUM_LIT:1>:<EOL><INDENT>arg.add_value_types(sig_arg["<STR_LIT>"])<EOL>log.debug(f'<STR_LIT>')<EOL><DEDENT><DEDENT>elif arg.type in ["<STR_LIT>", "<STR_LIT>", "<STR_LIT>"]:<EOL><INDENT>log.debug(f"<STR_LIT>")<EOL>arg.add_value_types(sig_arg["<STR_LIT>"])<EOL>log.debug(f'<STR_LIT>')<EOL><DEDENT><DEDENT><DEDENT><DEDENT>for arg in args:<EOL><INDENT>if arg.__class__.__name__ in ["<STR_LIT>", "<STR_LIT>"]:<EOL><INDENT>log.debug(f"<STR_LIT>")<EOL><DEDENT><DEDENT>return (valid_function, messages)<EOL>
Check function args - return message if function args don't match function signature

    Called from validate_functions

    We have following types of arguments to validate:
        1. Required, position_dependent arguments, e.g. p(HGNC:AKT1), NSArg HGNC:AKT1 is required and must be first argument
        2. Optional, position_dependent arguments, e.g. pmod(P, T, 308) - T and 308 are optional and position_dependent
        3. Optional, e.g. loc() modifier can only be found once, but anywhere after the position_dependent arguments
        4. Multiple, e.g. var(), can have more than one var() modifier in p() function

    Args:
        args (Union['Function', 'NSArg', 'StrArg']): AST Function arguments
        signatures (Mapping[str, Any]): function signatures from spec_dict, may be more than one per function
        function_name (str): passed in to improve error messaging

    Returns:
        Tuple[bool, List[str]]: (function_valid?, list of error messages per signature)