def get_file(*args, **kwargs):
    return util.normalize_newlines(get_file_as_bytes(*args, **kwargs).decode('utf-8')) def lib_of_filename(filename, exts=('.v', '.glob'), **kwargs):
    kwargs = fill_kwargs(kwargs)
    filename, libname = lib_of_filename_helper(filename, libnames=tuple(kwargs['libnames']), non_recursive_libnames=tuple(kwargs['non_recursive_libnames']), exts=exts)
#    if '.' in filename:
#        # TODO: Do we still need this warning?
#        kwargs['log']("WARNING: There is a dot (.) in filename %s; the library conversion probably won't work." % filename)
    return libname def get_coq_output(coqc_prog, coqc_prog_args, contents, timeout_val, cwd=None, is_coqtop=False, pass_on_stdin=False, verbose_base=1, retry_with_debug_when=(lambda output: 'is not a compiled interface for this version of OCaml' in output), **kwargs):
    """Returns the coqc output of running through the given
    contents.  Pass timeout_val = None for no timeout."""
    if timeout_val is not None and timeout_val < 0 and get_timeout(coqc_prog) is not None:
        return get_coq_output(coqc_prog, coqc_prog_args, contents, get_timeout(coqc_prog), cwd=cwd, is_coqtop=is_coqtop, pass_on_stdin=pass_on_stdin, verbose_base=verbose_base, retry_with_debug_when=retry_with_debug_when, **kwargs)

    key, file_name, cmds, input_val, cleaner = prepare_cmds_for_coq_output(coqc_prog, coqc_prog_args, contents, cwd=cwd, timeout_val=timeout_val, is_coqtop=is_coqtop, pass_on_stdin=pass_on_stdin, verbose_base=verbose_base, **kwargs)

    if key in COQ_OUTPUT.keys():
        cleaner()
        return COQ_OUTPUT[key][1]

    start = time.time()
    ((stdout, stderr), returncode) = memory_robust_timeout_Popen_communicate(kwargs['log'], cmds, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, stdin=subprocess.PIPE, timeout=(timeout_val if timeout_val is not None and timeout_val > 0 else None), input=input_val, cwd=cwd)
    finish = time.time()
    runtime = finish - start
    kwargs['log']('\nretcode: %d\nstdout:\n%s\n\nstderr:\n%s\nruntime:\n%f\n\n' % (returncode, util.s(stdout), util.s(stderr), runtime),
                  level=verbose_base + 1)
    if get_timeout(coqc_prog) is None and timeout_val is not None:
        set_timeout(coqc_prog, 3 * max((1, int(math.ceil(finish - start)))), **kwargs)
    cleaner()
    COQ_OUTPUT[key] = (file_name, (clean_output(util.s(stdout)), tuple(cmds), returncode, runtime))
    kwargs['log']('Storing result: COQ_OUTPUT[%s]:\n%s' % (repr(key), repr(COQ_OUTPUT[key])),
                  level=verbose_base + 2)
    if retry_with_debug_when(COQ_OUTPUT[key][1][0]):
        debug_args = get_coq_debug_native_compiler_args(coqc_prog)
        kwargs['log']('Retrying with %s...' % ' '.join(debug_args),
                      level=verbose_base - 1)
        return get_coq_output(coqc_prog, list(debug_args) + list(coqc_prog_args), contents, timeout_val, cwd=cwd, is_coqtop=is_coqtop, pass_on_stdin=pass_on_stdin, verbose_base=verbose_base, retry_with_debug_when=(lambda output: False), **kwargs)
    return COQ_OUTPUT[key][1] def lib_of_filename(filename, exts=('.v', '.glob'), **kwargs):
    kwargs = fill_kwargs(kwargs)
    filename, libname = lib_of_filename_helper(filename, libnames=tuple(kwargs['libnames']), non_recursive_libnames=tuple(kwargs['non_recursive_libnames']), exts=exts)
#    if '.' in filename:
#        # TODO: Do we still need this warning?
#        kwargs['log']("WARNING: There is a dot (.) in filename %s; the library conversion probably won't work." % filename)
    return libname def norm_libname(lib, **kwargs):
    kwargs = fill_kwargs(kwargs)
    filename = filename_of_lib(lib, **kwargs)
    if os.path.isfile(filename):
        return lib_of_filename(filename, **kwargs)
    else:
        return lib def memoize(f):
    """ Memoization decorator for a function taking one or more arguments. """
    class memodict(dict):
        def __getitem__(self, *key, **kwkey):
            return dict.__getitem__(self, (tuple(key), tuple((k, kwkey[k]) for k in sorted(kwkey.keys()))))

        def __missing__(self, key):
            args, kwargs = key
            self[key] = ret = f(*args, **dict(kwargs))
            return ret

    return memodict().__getitem__ def get_coqc_version(coqc_prog, **kwargs):
    kwargs['log']('Running command: "%s"' % '" "'.join([coqc_prog, "-q", "-v"]), level=2)
    return get_coqc_version_helper(coqc_prog) def get_coqtop_version(coqtop_prog, **kwargs):
    kwargs['log']('Running command: "%s"' % '" "'.join([coqtop_prog, "-q", "-v"]), level=2)
    return get_coqtop_version_helper(coqtop_prog) def get_coqc_help(coqc_prog, **kwargs):
    kwargs['log']('Running command: "%s"' % '" "'.join([coqc_prog, "-q", "--help"]), level=2)
    return get_coqc_help_helper(coqc_prog) @memoize
def get_coq_accepts_top(coqc):
    temp_file = tempfile.NamedTemporaryFile(suffix='.v', dir='.', delete=True)
    temp_file_name = temp_file.name
    p = subprocess.Popen([coqc, "-q", "-top", "Top", temp_file_name], stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
    (stdout, stderr) = p.communicate()
    temp_file.close()
    clean_v_file(temp_file_name)
    return '-top: no such file or directory' not in util.s(stdout) def group_coq_args(args, coqc_help, topname=None, is_coq_makefile=False):
    bindings, unrecognized_bindings = group_coq_args_split_recognized(args, coqc_help, topname=topname, is_coq_makefile=is_coq_makefile)
    return bindings + [tuple([v]) for v in unrecognized_bindings] def add_libname_arguments(parser): add_libname_arguments_gen(parser, passing='') def update_env_with_libnames(env, args, default=(('.', 'Top'), ), include_passing=False, use_default=True, use_passing_default=True):
    all_keys = ('libnames', 'non_recursive_libnames', 'ocaml_dirnames', '_CoqProject', '_CoqProject_v_files', '_CoqProject_unknown')
    passing_opts = ('', ) if not include_passing else ('', 'passing_', 'nonpassing_')
    for passing in passing_opts:
        for key in all_keys:
            env[passing + key] = []
        if getattr(args, passing + 'CoqProjectFile'):
            for f in getattr(args, passing + 'CoqProjectFile'):
                env[passing + '_CoqProject'] = f.read()
                f.close()
        process_CoqProject(env, env[passing + '_CoqProject'], passing=passing)
        env[passing + 'libnames'].extend(getattr(args, passing + 'libnames'))
        env[passing + 'non_recursive_libnames'].extend(getattr(args, passing + 'non_recursive_libnames'))
        env[passing + 'ocaml_dirnames'].extend(getattr(args, passing + 'ocaml_dirnames'))
    if include_passing:
        # The nonpassing_ prefix is actually temporary; the semantics
        # are that, e.g., libnames = libnames + nonpassing_libnames,
        # while passing_libnames = libnames + passing_libnames
        for key in all_keys:
            env['passing_' + key] = env[key] + env['passing_' + key]
            env[key] = env[key] + env['nonpassing_' + key]
            del env['nonpassing_' + key]
    if use_default:
        update_env_with_libname_default(env, args, default=default)
    if use_passing_default and include_passing:
        update_env_with_libname_default(env, args, default=default, passing='passing_') def add_logging_arguments(parser):
    parser.add_argument('--verbose', '-v', dest='verbose',
                        action='count',
                        help='display some extra information by default (does not impact --verbose-log-file)')
    parser.add_argument('--quiet', '-q', dest='quiet',
                        action='count',
                        help='the inverse of --verbose')
    parser.add_argument('--log-file', '-l', dest='log_files', nargs='+', type=argparse.FileType('w'),
                        default=[sys.stderr],
                        help='The files to log output to.  Use - for stdout.')
    parser.add_argument('--verbose-log-file', dest='verbose_log_files', nargs='+', type=TupleType(int, argparse.FileType('w')),
                        default=[],
                        help=(('The files to log output to at verbosity other than the default verbosity (%d if no -v/-q arguments are passed); ' +
                               'each argument should be a pair of a verbosity level and a file name. '
                               'Use - for stdout.') % DEFAULT_VERBOSITY)) def process_logging_arguments(args):
    if args.verbose is None: args.verbose = DEFAULT_VERBOSITY
    if args.quiet is None: args.quiet = 0
    args.verbose -= args.quiet
    args.log = make_logger([(args.verbose, f) for f in args.log_files]
                           + args.verbose_log_files)
    del args.quiet
    del args.verbose
    return args DEFAULT_LOG = make_logger([(DEFAULT_VERBOSITY, sys.stderr)]) LOG_ALWAYS=None def has_dir_binding(args, coqc_help, file_name=None):
    kwargs = dict()
    if file_name is not None: kwargs['topname'] = topname_of_filename(file_name)
    bindings = group_coq_args(args, coqc_help, **kwargs)
    return any(i[0] in ('-R', '-Q') for i in bindings) def deduplicate_trailing_dir_bindings(args, coqc_help, coq_accepts_top, file_name=None):
    kwargs = dict()
    if file_name is not None: kwargs['topname'] = topname_of_filename(file_name)
    bindings = group_coq_args(args, coqc_help, **kwargs)
    ret = []
    for binding in bindings:
        if coq_accepts_top or binding[0] != '-top':
            ret.extend(binding)
    return tuple(ret) def process_maybe_list(ls, log=DEFAULT_LOG):
    if ls is None: return tuple()
    if isinstance(ls, str): return tuple([ls])
    if isinstance(ls, tuple): return ls
    if isinstance(ls, list): return tuple(ls)
    log("Unknown type '%s' of list '%s'" % (str(type(ls)), repr(ls)))
    return tuple(ls) def clean_v_file(file_name):
    clean_extra_coq_files(file_name, extra_exts=('.v',)) def read_from_file(file_name):
    return util.normalize_newlines(read_bytes_from_file(file_name).decode('utf-8')) def write_to_file(file_name, contents, *args, **kwargs):
    return write_bytes_to_file(file_name, contents.replace('\n', os.linesep).encode('utf-8'), *args, **kwargs) def restore_file(file_name, backup_ext='.bak', backup_backup_ext='.unbak'):
    if not os.path.exists(file_name + backup_ext):
        raise IOError
    if os.path.exists(file_name):
        if backup_backup_ext:
            backup(file_name, backup_backup_ext)
        else:
            os.remove(file_name)
    os.rename(file_name + backup_ext, file_name) PY3 = False
import tempfile, sys, os, re
import custom_arguments
import diagnose_error
from argparse_compat import argparse
from import_util import get_file, lib_of_filename
from diagnose_error import get_coq_output
from import_util import lib_of_filename, norm_libname
from memoize import memoize
from coq_version import get_coqc_version, get_coqtop_version, get_coqc_help, get_coq_accepts_top, group_coq_args
from custom_arguments import add_libname_arguments, update_env_with_libnames, add_logging_arguments, process_logging_arguments, DEFAULT_LOG, LOG_ALWAYS
from binding_util import has_dir_binding, deduplicate_trailing_dir_bindings, process_maybe_list
from file_util import clean_v_file, read_from_file, write_to_file, restore_file
from util import PY3
if PY3: from util import raw_input
        elif '.' not in ident:
            yield ident
        else:
            idx = ident.index('.')
            overlap, rest = ident[:idx], ident[idx:]
            if libname[-(idx+1):] == '.' + overlap:
                yield libname + rest
            else:
                #raw_input((ident, libname))
                #yield ident
                continue

if __name__ == '__main__':
    try:
        args = process_logging_arguments(parser.parse_args())
    except argparse.ArgumentError as exc:
        if exc.message == 'expected one argument':
            exc.reraise('\nNote that argparse does not accept arguments with leading dashes.\nTry --foo=bar or --foo " -bar", if this was your intent.\nSee Python issue 9334.')
        else:
            exc.reraise()
    def prepend_coqbin(prog):
        if args.coqbin != '':
            return os.path.join(args.coqbin, prog)
        else:
            return prog
    env = {
        'log': args.log,
        'coqc': prepend_coqbin(args.coqc),
        'coqtop': prepend_coqbin(args.coqtop),
        'coqc_args': tuple(i.strip()
                           for i in process_maybe_list(args.coq_args, log=args.log)),
        'coqc_is_coqtop': args.coqc_is_coqtop,
        'temp_file_name': '',
    }

    env['remove_temp_file'] = False
    if env['temp_file_name'] == '':
        temp_file = tempfile.NamedTemporaryFile(suffix='.v', dir='.', delete=False)
        env['temp_file_name'] = temp_file.name
        temp_file.close()
        env['remove_temp_file'] = True

    if env['coqc_is_coqtop']:
        if env['coqc'] == 'coqc': env['coqc'] = env['coqtop']
        env['make_coqc'] = os.path.join(SCRIPT_DIRECTORY, 'coqtop-as-coqc.sh') + ' ' + env['coqc']

    coqc_help = get_coqc_help(env['coqc'], **env)
    coqc_version = get_coqc_version(env['coqc'], **env)

    if has_dir_binding(env['coqc_args'], coqc_help=coqc_help):
        update_env_with_libnames(env, args, default=tuple([]))
    else:
        update_env_with_libnames(env, args)

    for dirname, libname in env['libnames']:
        env['coqc_args'] = tuple(list(env['coqc_args']) + ['-R', dirname, libname])
    for dirname, libname in env['non_recursive_libnames']:
        env['coqc_args'] = tuple(list(env['coqc_args']) + ['-Q', dirname, libname])
    for dirname in env['ocaml_dirnames']:
        env['coqc_args'] = tuple(list(env['coqc_args']) + ['-I', dirname])
    env['coqc_args'] = deduplicate_trailing_dir_bindings(env['coqc_args'], coqc_help=coqc_help, coq_accepts_top=get_coq_accepts_top(env['coqc']))

    try:
        env['log']('Listing identifiers...')
        unknown = []
        closed_idents = []
        open_idents = []
        errors = []
        ignore_header = ('Welcome to Coq', '[Loading ML file')
        error_header = ('Toplevel input, characters',)
        for filename in sorted(env['_CoqProject_v_files']):
            env['log']('Qualifying identifiers in %s...' % filename, level=2)
            env['log']('Printing assumptions in %s...' % filename, max_level=2)
            libname = lib_of_filename(filename, **env)
            require_statement = 'Require %s.\n' % libname
            search_code = r"""%s
Set Search Output Name Only.
SearchPattern _ inside %s.""" % (require_statement, libname)
            output, cmds, retcode, runtime = get_coq_output(env['coqc'], env['coqc_args'], search_code, 0, is_coqtop=env['coqc_is_coqtop'], verbose_base=3, **env)
            identifiers = sorted(fix_identifiers(set(i.strip() for i in output.split('\n') if i.strip()), libname))
            print_assumptions_code = require_statement + '\n'.join('Locate %s.\nPrint Assumptions %s.' % (i, i) for i in identifiers)
            env['log']('Printing assumptions...', level=2)
            output, cmds, retcode, runtime = get_coq_output(env['coqtop'], env['coqc_args'], print_assumptions_code, 0, is_coqtop=True, pass_on_stdin=True, verbose_base=3, **env)
            i = 0
            statements = output.split('\nCoq <')
            while i < len(statements):
                if i+1 < len(statements) and ' Closed under the global context ' in statements[i+1].replace('\n', ' '):
                    last, ctype = get_constant_name_from_locate(statements[i])
                    closed_idents.append((last, ctype))
                    env['log']('Closed: %s (%s)' % (last, ctype), level=2)
                    i += 2
                elif i+1 < len(statements) and 'Axioms:' in statements[i+1].replace('\n', ' '):
                    last, ctype = get_constant_name_from_locate(statements[i])
                    open_idents.append((last, ctype, statements[i+1]))
                    env['log']('OPEN: %s (%s)' % (last, ctype))
                    env['log'](statements[i+1], level=3)
                    i += 2
                elif not statements[i].strip():
                    i += 1
                else:
                    found_ignore, found_error = False, False
                    for header in ignore_header:
                        if statements[i].strip()[:len(header)] == header:
                            found_ignore = True
                            env['log']('Ignoring: %s' % statements[i], level=3)
                    for header in ignore_header:
                        if statements[i].strip()[:len(header)] == header:
                            found_error = True
                    if not found_ignore:
                        if found_error:
                            errors.append(statements[i])
                            env['log']('ERROR: %s' % statements[i])
                        else:
                            env['log']('UNKNOWN: %s' % statements[i])
                            unknown.append(statements[i])
                    i += 1
        env['log']('Identifiers which are not closed under the global context:\n%s' % '\n'.join(ident[0] for ident in open_idents),
                   level=LOG_ALWAYS)
    finally:
        if env['remove_temp_file']:

            clean_v_file(env['temp_file_name'])