#!/usr/bin/env python
import filecmp
import glob
import os
import shutil
import subprocess
import sys

from waflib.extras import autowaf as autowaf
import waflib.Logs as Logs, waflib.Options as Options

# Version of this package (even if built as a child)
RESP_VERSION       = '0.0.0'
RESP_MAJOR_VERSION = '0'

# Library version (UNIX style major, minor, micro)
# major increment <=> incompatible changes
# minor increment <=> compatible changes (additions)
# micro increment <=> no interface changes
# Resp uses the same version number for both library and package
RESP_LIB_VERSION = RESP_VERSION

# Variables for 'waf dist'
APPNAME = 'resp'
VERSION = RESP_VERSION

# Mandatory variables
top = '.'
out = 'build'

def options(opt):
    opt.load('compiler_c')
    opt.load('compiler_cxx')
    autowaf.set_options(opt)

def configure(conf):
    conf.load('compiler_c')
    conf.load('compiler_cxx')
    autowaf.configure(conf)
    autowaf.display_header('Resp Configuration')

    conf.env.append_unique('CFLAGS', '-std=c99')
    conf.env.append_unique('CXXFLAGS', '-std=c++11')

    conf.check_cfg(
        path         = 'llvm-config-3.1',
        args         = '--cppflags --ldflags --libs core jit native codegen ipo',
        package      = '',
        uselib_store = 'LLVM',
        mandatory    = False)

    if not conf.is_defined('HAVE_LLVM'):
        conf.check_cfg(
            path         = 'llvm-config-3.0',
            args         = '--cppflags --ldflags --libs core jit native codegen ipo',
            package      = '',
            uselib_store = 'LLVM',
            mandatory    = False)

def build(bld):
    source = '''
        src/compile.cpp
        src/constrain.cpp
        src/cps.cpp
        src/depoly.cpp
        src/expand.cpp
        src/flatten.cpp
        src/gc.cpp
        src/lift.cpp
        src/llvm.cpp
        src/parse.cpp
        src/pprint.cpp
        src/repl.cpp
        src/resp.cpp
        src/simplify.cpp
        src/tlsf.c
        src/unify.cpp
    '''

    obj = bld(features  = 'cxx cxxprogram',
              source    = source,
              target    = 'resp',
              uselib    = 'LLVM',
              linkflags = ['-rdynamic'])

def test(ctx):
    def run_test(prog, correct_out):
        try:
            out = subprocess.check_output(['./build/resp', prog]).strip()
            if out == correct_out:
                Logs.info("PASS: %s" % prog)
            else:
                Logs.error("FAIL:     %s" % prog)
                Logs.error("Expected: %s" % correct_out)
                Logs.error("Got:      %s" % out)
        except:
            Logs.error("ERROR:    %s" % prog)

    # Basic lexical sanity
    run_test('./test/mac.scm',         '#f : Bool')
    run_test('./test/def.scm',         '4 : Int')
    run_test('./test/deffn.scm',       '3 : Int')
    run_test('./test/inlinefn.scm',    '2 : Int')
    run_test('./test/nest.scm',        '8 : Int')
    
    # Basic data types
    run_test('./test/string.scm',      '"Hello, world!" : String')
    run_test('./test/tup.scm',         '5 : Int')
    
    # Recursive arithmetic functions
    run_test('./test/fac.scm',         '720 : Int')
    run_test('./test/ack.scm',         '8189 : Int')
    
    # Closures
    run_test('./test/closure.scm',     '6 : Int')
    run_test('./test/noargs.scm',      '6 : Int')

    # Derived expressions
    run_test('./test/let.scm',         '42 : Int')
    run_test('./test/cond.scm',        '2.00000 : Float')

    # Algebraic data types
    run_test('./test/match.scm',       '12.0000 : Float')

    # Quoting
    run_test('./test/quote.scm',       '4 : Int')