#!/usr/bin/env python
#
#                     The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
#
# This script attempts to be a drop-in replacement for gcc.
#
##===----------------------------------------------------------------------===##

import sys
import subprocess

def error(message):
    print >> sys.stderr, 'ccc: ' + message
    sys.exit(1)

def run(args):
    print >> sys.stderr, ' '.join(args)
    code = subprocess.call(args)
    if code > 255:
        code = 1
    if code:
        sys.exit(code)

def preprocess(args):
    command = 'clang -E'.split()
    run(command + args)

def compile(args):
    command = 'clang -emit-llvm-bc'.split()
    run(command + args)

def link(args):
    command = 'llvm-ld -native -disable-internalize'.split()
    run(command + args)

def extension(path):
    return path.split(".")[-1]

def changeextension(path, newext):
    i = path.rfind('.')
    if i < 0:
        return path
    j = path.rfind('/', 0, i)
    print path
    if j < 0:
        return path[:i] + "." + newext
    return path[j+1:i] + "." + newext

def inferlanguage(extension):
    if extension == "c":
        return "c"
    elif extension in ["cpp", "cc"]:
        return "c++"
    elif extension == "i":
        return "c-cpp-output"
    elif extension == "m":
        return "objective-c"
    elif extension == "mi":
        return "objective-c-cpp-output"
    else:
        return "unknown"

def main(args):
    action = 'link'
    output = ''
    compile_opts = []
    link_opts = []
    files = []
    save_temps = 0
    language = ''
    
    i = 0
    while i < len(args):
        arg = args[i]

        # Modes ccc supports
        if arg == '-E':
            action = 'preprocess'
        if arg == '-c':
            action = 'compile'
        if arg.startswith('-print-prog-name'):
            action = 'print-prog-name'
        if arg == '-save-temps':
            save_temps = 1

        # Options with no arguments that should pass through
        if arg in ['-v']:
            compile_opts.append(arg)
            link_opts.append(arg)
        
        # Options with one argument that should be ignored
        if arg in ['--param', '-arch', '-u']:
            i += 1

        # Prefix matches for the compile mode
        if arg[:2] in ['-D', '-I', '-U', '-F']:
            if not arg[2:]:
                arg += args[i+1]
                i += 1
            compile_opts.append(arg)
        if arg[:5] in ['-std=']:
            compile_opts.append(arg)

        # Options with one argument that should pass through
        if arg in ['-include']:
            compile_opts.append(arg)
            compile_opts.append(args[i+1])
            i += 1

        # Prefix matches for the link mode
        if arg[:2] in ['-l', '-L', '-O', '-F']:
            if arg == '-O': arg = '-O1'
            if arg == '-Os': arg = '-O2'
            link_opts.append(arg)

        # Options with one argument that should pass through
        if arg in ['-framework']:
            link_opts.append(arg)
            link_opts.append(args[i+1])
            i += 1

        # Input files
        if arg == '-filelist':
            f = open(args[i+1])
            for line in f:
                files.append(line.strip())
            f.close()
            i += 1
        if arg == '-x':
            language = args[i+1]
            i += 1
        if arg[0] != '-':
            files.append(arg)

        # Output file
        if arg == '-o':
            output = args[i+1]
            i += 1

        i += 1

    if action == 'print-prog-name':
        # assume we can handle everything
        print sys.argv[0]
        return

    if not files:
        error('no input files')

    if action == 'preprocess' or save_temps:
        for i, file in enumerate(files):
            if not language:
                language = inferlanguage(extension(file))
            if save_temps and action != 'preprocess':
                # Need a temporary output file
                if language == 'c':
                    poutput = changeextension(file, "i");
                elif language == 'objective-c':
                    poutput = changeextension(file, "mi");
                else:
                    poutput = changeextension(file, "tmp." + extension(file))
                files[i] = poutput
            else:
                poutput = output
            if poutput:
                args = ['-x', language, '-o', poutput, file] + compile_opts
            else:
                args = ['-x', language, file] + compile_opts
            preprocess(args)
            # Discard the explicit language after used once
            language = ''

    if action == 'compile' or save_temps:
        for i, file in enumerate(files):
            if not language:
                language = inferlanguage(extension(file))
            if save_temps and action != "compile":
                # Need a temporary output file
                coutput = changeextension(file, "o");
                files[i] = coutput
            elif not output:
                coutput = changeextension(file, "o")
            else:
                coutput = output
            args = ['-x', language, '-o', coutput, file] + compile_opts
            compile(args)
            language = ''

    if action == 'link':
        for i, file in enumerate(files):
            ext = extension(file)
            if ext != "o" and ext != "a":
                out = changeextension(file, "o")
                args = ['-o', out, file] + compile_opts
                compile(args)
                files[i] = out
        if not output:
            output = 'a.out'
        args = ['-o', output] + link_opts + files
        link(args)

if __name__ == '__main__':
    main(sys.argv[1:])
