#!/usr/bin/env bash

# This script runs the regression tests in src/regression.
# It also compiles the tests in benchmark/tests

set -e

name=`basename $0`

usage () {
        echo >&2 "usage: $name [-cross target] [-run-only target] [-short] [mlton flags ...]"
        exit 1
}

cross='false'
fail='false'
runOnly='false'
short='false'
while [ "$#" -gt 0 ]; do
        case "$1" in
        -cross)
                cross='true'
                shift
                if [ "$#" = 0 ]; then
                        usage
                fi
                crossTarget="$1"
                shift
                ;;
        -fail)
                fail='true'
                shift
                ;;
        -run-only)
                runOnly='true'
                shift
                if [ "$#" = 0 ]; then
                        usage
                fi
                crossTarget="$1"
                shift
                ;;
        -short)
                short='true'
                shift
                ;;
        *)
                flags="$@"
                break
                ;;
        esac
done

dir=`dirname $0`
src=`cd $dir/.. && pwd`
bin="$src/build/bin"
lib="$src/build/lib"
mlton="$bin/mlton"
flags="-type-check true $flags"
if $cross; then
        flags="$flags -target $crossTarget -stop g"
fi
cont='callcc.sml callcc2.sml callcc3.sml once.sml'
flatArray='finalize.sml flat-array.sml flat-array.2.sml'
intInf='conv.sml conv2.sml fixed-integer.sml harmonic.sml int-inf.*.sml slow.sml slower.sml smith-normal-form.sml'
signal='finalize.sml signals.sml signals2.sml suspend.sml weak.sml'
thread='thread0.sml thread1.sml thread2.sml mutex.sml prodcons.sml same-fringe.sml timeout.sml'
world='world1.sml world2.sml world3.sml world4.sml world5.sml world6.sml'
tmp=/tmp/z.regression.$$
PATH=$bin:$src/bin/.:$PATH

eval `$lib/platform`

compFail () {
        echo "compilation of $f failed with $flags"
}

$mlton -verbose 1 || echo 'no mlton present'
echo "flags = $flags"

cd $src/regression

if $fail; then
        for f in `ls fail/*.sml`; do
                echo "testing $f"
                ( $mlton $flags -stop tc $f >/dev/null 2>&1 &&
                        echo "compilation of $f should have failed but did not" ) ||
                        true
        done
        exit 0
fi

forMinGW='false'
if [ `host-os` = mingw ]; then
	forMinGW='true'
fi
case $crossTarget in
*mingw)
	forMinGW='true'
;;
esac

for f in `ls *.sml`; do
        f=`basename $f .sml`
        case `host-os` in
        cygwin|mingw)
                case "$f" in
                echo|signals|socket|suspend|textio.2|thread2|world*)
                        continue
                ;;
                esac
        ;;
        esac
        case `host-os` in
        mingw)
                case "$f" in
                cmdline|command-line|filesys|mutex|posix-exit|prodcons|signals2|timeout|unixpath)
                        continue
                ;;
                esac
        esac
        case "$f" in
        serialize)
                continue
        ;;
	esac
        echo "testing $f"
        case "$f" in
        exnHistory*)
                extraFlags="-const 'Exn.keepHistory true'"
        ;;
        *)
                extraFlags=""
        ;;
        esac
	if (! $runOnly); then
                mlb="$f.mlb"
                echo "\$(SML_LIB)/basis/basis.mlb
                        \$(SML_LIB)/basis/mlton.mlb
                        \$(SML_LIB)/basis/sml-nj.mlb
                        ann 
                                \"allowFFI true\"
                                \"allowOverload true\"
                                \"nonexhaustiveMatch ignore\"
                                \"redundantMatch ignore\"
                        in $f.sml 
                        end" >$mlb
                cmd="$mlton $flags $extraFlags -output $f $mlb"
                eval $cmd
                rm $mlb
                if [ "$?" -ne '0' ] || ((! $cross) && [ ! -x "$f" ]); then
                        compFail $f
                fi
	else
                case $crossTarget in
                *mingw)
                        libs='-lws2_32 -lkernel32 -lpsapi -lnetapi32'
                ;;
                *solaris)
                        libs='-lnsl -lsocket -lrt'
                ;;
                *)
                        libs=''
                ;;
                esac
                libs="-lmlton -lgmp $libs -lgdtoa -lm"
                # Must use $f.[0-9].[cS], not $f.*.[cS], because the
                # latter will include other files, e.g. for finalize,
                # it will also include finalize.2.
                files="$f.[0-9].[cS]"
                if [ 0 -ne `ls $f.[0-9][0-9].[cS] 2>/dev/null | wc -l` ]; then 
                        files="$files $f.[0-9][0-9].[cS]"
                fi
                gcc -o $f -w -O1                                \
                        -I "../build/lib/include"               \
                        -L"../build/lib/$crossTarget"           \
                        -L/usr/pkg/lib                          \
                        -L/usr/local/lib                        \
                        $files $libs
	fi
        if [ ! -r $f.nonterm -a $cross = 'false' -a -x $f ]; then
                nonZeroMsg='Nonzero exit status.'
		if $forMinGW; then
                       nonZeroMsg="$nonZeroMsg"'\r'
		fi
                ( ./$f || echo -e "$nonZeroMsg" ) >$tmp 2>&1 
                if [ -r $f.ok ]; then
                        compare="$f.$HOST_ARCH-$HOST_OS.ok"
                        if [ ! -r $compare ]; then
                                compare="$f.ok"
                        fi
			if $forMinGW; then
                                compare="$f.sed.ok"
                                /c/cygwin/bin/sed 's/$/\r/' <"$f.ok" >"$compare"
			fi
                        if ! diff $compare $tmp; then
                                echo "difference with $flags"
                        fi
                fi
        fi
done
if $cross || $runOnly || $short; then
        exit 0
fi
mmake clean >/dev/null
cd $src/benchmark/tests
for f in `ls *.sml`; do
        f=`basename $f .sml`
        tmpf=/tmp/$f.$$
        case "$f" in
        fxp|hamlet)
                echo "skipping $f"
        ;;
        *)
                        echo "testing $f"
                echo "val _ = Main.doit 0" | cat $f.sml - > $tmpf.sml
                $mlton -output $tmpf $flags                     \
                        -default-ann 'nonexhaustiveMatch ignore'\
                        -default-ann 'redundantMatch ignore'    \
                        $tmpf.sml
                if [ $? -ne 0 ]; then
                        compFail $f
                fi
                rm -f $tmpf $tmpf.sml
        ;;
        esac
done 
mmake clean >/dev/null
cd $src
for f in mllex mlyacc mlprof; do
    tmpf=/tmp/$f.$$
    cd $src/$f
    case "$f" in
    foobar)
            echo "skipping $f"
    ;;
    *)
        echo "testing $f"
        mmake -W $f >/dev/null
        $mlton $flags -output $tmpf $f.mlb
        if [ $? -ne 0 ]; then
                compFail $f
        fi
        rm -f $tmpf
    ;;
    esac
done

rm -f $tmp
