#---------------------------------------------------------------------------#
# vim: ts=8 sw=8 noexpandtab ft=make
#---------------------------------------------------------------------------#

TESTS_DIR = ..
THIS_DIR = debugger
MAYBE_J1 =

#---------------------------------------------------------------------------#

RETRY_PROGS = \
	all_solutions			\
	browser_test			\
	chooser_tag_test		\
	io_tab_goto			\
	lambda_expr			\
	mdb_command_test		\
	queens				\
	retry				\
	scripts				\
	tabled_read			\
	tabled_read_unitize		\
	tabled_read_decl		\
	tabled_typeclass		\
	tailrec1

NONRETRY_PROGS = \
	ambiguity			\
	breakpoints			\
	browse_packed			\
	browse_pretty			\
	class_decl			\
	cmd_quote			\
	cond				\
	debugger_regs			\
	dice				\
	direct_arg_test			\
	double_print			\
	exception_cmd			\
	exception_value			\
	exception_vars			\
	existential_type_classes	\
	exported_eqv_type		\
	field_names			\
	foreign_type			\
	higher_order			\
	implied_instance		\
	interpreter			\
	label_layout			\
	lambdatest			\
	list_cmd			\
	lval_desc_array			\
	mdbrc_test			\
	multi_parameter			\
	mutrec				\
	mutrec_higher_order		\
	pack				\
	poly_io_retry_1			\
	poly_io_retry_2			\
	polymorphic_ground_term		\
	polymorphic_output		\
	print_goal			\
	print_io_actions		\
	print_table			\
	queens_rep			\
	resume_typeinfos		\
	save				\
	shell				\
	switch_on_unbounded		\
	synth_attr			\
	synth_attr_impure		\
	type_desc_test			\
	uci_index			\
	user_event_1			\
	user_event_2

# We currently don't pass this test.
#	deeply_nested_typeinfo
# This test is currently not useful.
#	output_term_dep

# Since the `interactive' test case requires the use of shared libraries,
# this means it won't work properly if the static libraries are linked
# (as is done by tools/bootcheck and tools/lmc).
# So we only enable it if LINK_STATIC is not set.
#
# The value of LINK_STATIC is normally in set in ../../Mmake.workspace,
# which we include indirectly via ../Mmake.common. However, we include
# ./Mmake.common only later on in this file, because ../Mmake.commmon
# depends on the value of the TESTS make variable, and hence on the value
# of PROGS, part of which we are trying to compute here. We resolve this
# circularity by adding a duplicate copy of the code setting LINK_STATIC.

ifneq ($(origin WORKSPACE),undefined)
    LINK_STATIC = yes
else
    ifeq ($(origin LINK_STATIC),undefined)
        LINK_STATIC = no
    endif
endif

ifneq ($(LINK_STATIC),no)
    INTERACTIVE_PROGS =
else
    INTERACTIVE_PROGS = \
	interactive
endif

# Declarative debugging grades don't support trace level shallow,
# so we execute the tests exercising shallow tracing only in grades
# other than .decldebug grades.
ifneq "$(findstring decldebug,$(GRADE))" ""
    SHALLOW_PROGS =
else
    SHALLOW_PROGS = \
	shallow				\
	user_event_shallow
endif

# Tabling is not compatible with parallel execution,
# so tests exercising tabling will never succeed in .par grades.
ifneq "$(findstring par,$(GRADE))" ""
    TABLING_PROGS =
else
    TABLING_PROGS = \
	fib				\
	loopcheck
endif

# The sensitive tests are so named because they are sensitive to details
# of code generation. We therefore execute them only in a minimal set of
# grades that still ensures good test coverage. For example, the tests
# in trailing grades without debugging do not test anything that the tests in
# .debug.tr grades do not.

SENSITIVE_PROGS0 = \
	completion			\
	nondet_stack

# NOTE Do NOT put quotes around the right hand sides of the next five lines.
# If you do, the first test will not do its job correctly.
G_PROF    = $(findstring prof,$(GRADE))
G_MEMPROF = $(findstring memprof,$(GRADE))
G_MM      = $(findstring mm,$(GRADE))
G_TSW     = $(findstring tsw,$(GRADE))
G_TSC     = $(findstring tsc,$(GRADE))
ifneq "$(G_PROF)$(G_MEMPROF)$(G_MM)$(G_TSW)$(G_TSC)" ""
    DIS = "x$(G_PROF)$(G_MEMPROF)$(G_MM)$(G_TSW)$(G_TSC)y"
    SENSITIVE_PROGS =
else
    ifeq "$(findstring debug,$(GRADE))" ""
        ifneq "$(findstring tr,$(GRADE))" ""
	    DIS = "b"
            SENSITIVE_PROGS =
        else
	    DIS = "c"
            SENSITIVE_PROGS = $(SENSITIVE_PROGS0)
        endif
    else
	DIS = "d"
        SENSITIVE_PROGS = $(SENSITIVE_PROGS0)
    endif
endif

# The no_inline_builtins test only works if the library is built with
# execution tracing enabled. Adding a `.exp2' file to allow it to be run
# in other grades would mean that we wouldn't detect a regression which
# caused builtins not to be traced with `--no-inline-builtins'.
ifeq "$(findstring debug,$(GRADE))" "debug"
    DEBUG_GRADE_PROGS = no_inline_builtins
else
    DEBUG_GRADE_PROGS =
endif

# The uci test matches its expected output only if the grade supports
# enumerated types. Currently all grades do support enumerated types.
ENUM_PROGS = uci

# The tests term_size_words and term_size_cells are each meant to be used
# in their respective grades only.
ifneq "$(findstring .tsw,$(GRADE))" ""
    TERM_SIZE_PROGS = term_size_words
else
    ifneq "$(findstring .tsc,$(GRADE))" ""
        TERM_SIZE_PROGS = term_size_cells
    else
        TERM_SIZE_PROGS =
    endif
endif

# The mmos_print test is meant to be used in mmos grades only.
ifneq "$(findstring mmos,$(GRADE))" ""
    MMOS_PROGS = mmos_print
else
    MMOS_PROGS =
endif

ALL_RETRY_PROGS = \
	$(RETRY_PROGS) \
	$(INTERACTIVE_PROGS)
ALL_NONRETRY_PROGS = \
	$(NONRETRY_PROGS) \
	$(SENSITIVE_PROGS) \
	$(SHALLOW_PROGS) \
	$(DEBUG_GRADE_PROGS) \
	$(ENUM_PROGS) \
	$(TERM_SIZE_PROGS) \
	$(MMOS_PROGS)

ifneq "$(findstring profdeep,$(GRADE))" ""
    # The retry command doesn't and will not work in deep profiling
    # grades (profdeep).
    #
    # Eventually, this should be DEBUGGER_PROGS0=$(ALL_NONRETRY_PROGS).
    # However, the code that is required to switch off the profiling
    # primitives in Mercury code invoked by the debugger (e.g. for
    # browsing) has not yet been implemented.
    DEBUGGER_PROGS0 =
else
    DEBUGGER_PROGS0 = $(ALL_NONRETRY_PROGS) $(ALL_RETRY_PROGS)
endif

# The tail call optimisation isn't supported in decldebug grades,
# so we don't run the tailrec1 test in those grades.
ifneq "$(findstring decldebug,$(GRADE))" ""
    DEBUGGER_PROGS = $(subst tailrec1,,$(DEBUGGER_PROGS0))
else
    DEBUGGER_PROGS = $(DEBUGGER_PROGS0)
endif

ifneq "$(filter hl% java% csharp%,$(GRADE))$(findstring par,$(GRADE))" ""
    # Mdb debugging is not designed to work either in MLDS grades
    # (hlc, csharp, java), or in parallel grades.
    PROGS =
else
    # Base grades `jump' and `fast' cannot be used with
    # stack layouts (which are required for tracing).
    ifneq "$(findstring asm_,$(GRADE))" ""
        PROGS = $(DEBUGGER_PROGS)
    else
        ifneq "$(findstring jump,$(GRADE))" ""
            PROGS =
        else
            ifneq "$(findstring fast,$(GRADE))" ""
                PROGS =
            else
                PROGS = $(DEBUGGER_PROGS)
            endif
        endif
    endif
endif

TESTS = $(sort $(PROGS))

# The minimum trace level in .decldebug grades is --trace decl.
ifneq "$(findstring decldebug,$(GRADE))" ""
    MCFLAGS += --trace decl
else
    MCFLAGS += --trace deep
endif
MLFLAGS += --trace

# Some of the test cases require a different input in decldebug grades,
# so we set INP to the appropriate extension to use for those tests.
# All other tests ignore this variable.
ifneq "$(findstring .decldebug,$(GRADE))" ""
    INP = inp2
else
    INP = inp
endif

# Module-specific options should go in Mercury.options so they can be found
# by `mmc --make'.
include Mercury.options

%.runtest: %.res ;

#---------------------------------------------------------------------------#

# We pipe the output through sed to avoid hard-coding dependencies on
# - particular line numbers in the standard library source code, or
# - particular addresses on the heap.
# These four patterns cover the needs of most of our test cases
# (though no test case needs them all, and some test cases need none).
SED_1 = -e 's/io.m:[0-9]*/io.m:NNNN/g'
SED_2 = -e 's/char.m:[0-9]*/char.m:NNNN/g'
# The extra spaces are there because we do not want to modify
# references to line numbers in mmos_print.m.
SED_3 = -e 's/ int.m:[0-9]*/ int.m:NNNN/g'
SED_4 = -e 's/c_pointer(0x[-0-9A-Fa-f]*)/c_pointer(0xXXXX)/g'
SED_ALL = $(SED_1) $(SED_2) $(SED_3) $(SED_4)

# NOTE This rule *must* precede the inclusion of ../Mmake.common, because
#
# - Mmake.common also defines an implicit rule to generate %.out from
#   % (and maybe %.inp), but with an action that does not involve mdb, and
#
# - in cases where two implicit rules both apply, make will use
#   the textually earlier one.
%.out: 	% %.inp
	$(MDB_STD) ./$* < $*.inp 2>&1 | sed $(SED_ALL) > $*.out 2>&1

include ../Mmake.common

#---------------------#

# Set up readline to make it easier to use completion non-interactively.
completion.out: completion completion.inp
	INPUTRC=completion.inputrc $(MDB) ./completion \
		< completion.inp 2>&1 | sed -e '/^$$/d' > completion.out 2>&1

# The exception_cmd, exception_vars and loopcheck tests
# are supposed to return a non-zero exit status, since they exit by throwing
# an exception. We strip the goal paths from their exception events, since
# the exact goal paths are dependent on optimization level. The stripping
# must be done outside the condition of the if-then-else.
exception_cmd.out: exception_cmd exception_cmd.inp
	if $(MDB_STD) ./exception_cmd < exception_cmd.inp	\
		> exception_cmd.tmp 2>&1;			\
	then							\
		sed -e '/EXCP/s/).*/)/' < exception_cmd.tmp	\
			> exception_cmd.out 2>&1;		\
		rm exception_cmd.tmp;				\
		false;						\
	else							\
		sed -e '/EXCP/s/).*/)/' < exception_cmd.tmp	\
			> exception_cmd.out 2>&1;		\
		rm exception_cmd.tmp;				\
		true;						\
	fi

dice.pass1: dice
	/bin/rm -f .mercury_trace_counts.*dice.*
	MERCURY_OPTIONS="--trace-count --deep-std-name" ./dice 1 2 3 4 && \
	mv .mercury_trace_counts.*dice.* dice.pass1

dice.pass2: dice dice.pass1
	/bin/rm -f .mercury_trace_counts.*dice.*
	MERCURY_OPTIONS="--trace-count --deep-std-name" ./dice 5 6 7 8 && \
	mv .mercury_trace_counts.*dice.* dice.pass2

dice.pass3: dice dice.pass2
	/bin/rm -f .mercury_trace_counts.*dice.*
	MERCURY_OPTIONS="--trace-count --deep-std-name" ./dice 10 11 100 && \
	mv .mercury_trace_counts.*dice.* dice.pass3

dice.passes: dice.pass1 dice.pass2 dice.pass3
	MERCURY_OPTIONS="--deep-std-name" \
	$(SLICE_DIR)mtc_union -o dice.passes dice.pass1 dice.pass2 dice.pass3

dice.fail: dice dice.passes
	/bin/rm -f .mercury_trace_counts.*dice.*
	MERCURY_OPTIONS="--trace-count --deep-std-name" ./dice 4 1 2 3 && \
	mv .mercury_trace_counts.*dice.* dice.fail

dice.out: dice dice.inp dice.passes dice.fail
	$(MDB_STD) ./dice 4 1 2 3 < dice.inp > dice.out 2>&1

# We need to pipe the output through sed to avoid hard-coding dependencies on
# particular line numbers in the standard library source code.
exception_value.out: exception_value exception_value.inp
	$(MDB_STD) ./exception_value < exception_value.inp 2>&1 | \
		sed -e 's/exception.m:[0-9]*/exception.m:NNNN/g' | \
		sed -e '/EXCP/s/).*/)/' > exception_value.out 2>&1

exception_vars.out: exception_vars exception_vars.inp
	if $(MDB_STD) ./exception_vars < exception_vars.inp	\
		> exception_vars.tmp 2>&1;			\
	then							\
		sed -e '/EXCP/s/).*/)/' < exception_vars.tmp	\
			> exception_vars.out 2>&1;		\
		rm exception_vars.tmp;				\
		false;						\
	else							\
		sed -e '/EXCP/s/).*/)/' < exception_vars.tmp	\
			> exception_vars.out 2>&1;		\
		rm exception_vars.tmp;				\
		true;						\
	fi

# We need to pipe the output through sed to avoid hard-coding dependencies on
# particular line numbers in the standard library source code.
existential_type_classes.out: existential_type_classes \
			existential_type_classes.inp
	$(MDB_STD) ./existential_type_classes < existential_type_classes.inp \
		2>&1 | sed 's/string.m:[0-9]*/string.m:NNNN/g' | \
		sed 's/int.m:[0-9]*/int.m:NNNN/g' | \
		sed 's/existential_type_classes.m:[0-9]*/existential_type_classes.m:NNNN/g' | \
		sed 's/c_pointer(0x[0-9A-Fa-f]*)/c_pointer(0xXXXX)/g' \
		> existential_type_classes.out

foreign_type.out: foreign_type foreign_type.inp
	$(MDB_STD) ./foreign_type < foreign_type.inp | \
		sed 's/coord, 0x[-0-9A-Fa-f]*/coord, 0xXXXX/g'  |\
		sed 's/coord, [0-9A-F][0-9A-F][0-9A-F]*/coord, 0xXXXX/g'  \
		> foreign_type.out 2>&1

# NOTE This program takes its own source code as input.
interpreter.out: interpreter interpreter.inp
	$(MDB_STD) ./interpreter interpreter.m < interpreter.inp \
		> interpreter.out 2>&1

loopcheck.out: loopcheck loopcheck.$(INP)
	if $(MDB) ./loopcheck < loopcheck.$(INP)		\
		> loopcheck.tmp 2>&1;				\
	then							\
		sed -e '/EXCP/s/).*/)/'				\
		    -e 's/require.m:[0-9]*/require.m:NNNN/g'	\
		    -e 's/label with no stack layout info/unknown label/' \
			< loopcheck.tmp > loopcheck.out 2>&1;	\
		rm loopcheck.tmp;				\
		false;						\
	else							\
		sed -e '/EXCP/s/).*/)/'				\
		    -e 's/require.m:[0-9]*/require.m:NNNN/g'	\
			< loopcheck.tmp	> loopcheck.out 2>&1;	\
		rm loopcheck.tmp;				\
		true;						\
	fi

interpreter.m: ../../samples/interpreter.m
	chmod u+w interpreter.m
	cp ../../samples/interpreter.m .
	chmod a-w interpreter.m

# The use of MDB_STD_NOINIT here is to override the default mdbrc file
# specified by the MDB make variable.
mdbrc_test.out: mdbrc_test mdbrc_test.inp mdbrc_test.mdbrc
	cp mdbrc_test.mdbrc .mdbrc
	$(MDB_STD_NOINIT) ./mdbrc_test < mdbrc_test.inp \
		> mdbrc_test.out 2>&1
	/bin/rm .mdbrc

# We insert the names of entry labels into the label table only in a few grades
# (e.g. profiling grades). The debugger's redo label is an entry label. To
# avoid spurious inconsistencies in the output, we filter out its name even
# when known.
nondet_stack.out: nondet_stack nondet_stack.inp
	$(MDB_STD) ./nondet_stack < nondet_stack.inp 2>&1 | \
		sed 's/entry label MR_do_trace_redo_fail_deep/label UNKNOWN/g' \
		| sed 's/unnamed label 0x.*/unnamed label/' \
		| sed 's/unnamed label [0-9a-fA-F][0-9a-fA-F]*/unnamed label/' \
		| sed 's/unnamed entry label 0x.*/unnamed entry label/' \
		| sed 's/unnamed entry label [0-9a-fA-F][0-9a-fA-F]*/unnamed entry label/' \
		| sed 's/label UNKNOWN .*/label UNKNOWN/' \
		| sed 's/nondet_stack.m:[0-9]*/nondet_stack.m:NNNN/g' \
		> nondet_stack.out 2>&1

resume_typeinfos.out: resume_typeinfos resume_typeinfos.inp
	$(MDB_STD) ./resume_typeinfos < resume_typeinfos.inp 2>&1 | \
		sed 's/resume_typeinfos.m:[0-9]*/resume_typeinfos.m:NNNN/g' \
		> resume_typeinfos.out 2>&1

# The value of web_browser_cmd will be system specific, so we pipe the output
# through sed and replace the system specific bit with a known character
# sequence.
save.out: save save.inp
	$(MDB) ./save < save.inp 2>&1 | \
	    sed 's/web_browser_cmd.*/web_browser_cmd ZZZ/g' | \
	    sed 's/^alias grep source.*$$/alias grep source ZZZ\/mdb_grep/' | \
	    sed 's/^alias open source.*$$/alias open source ZZZ\/mdb_open/' | \
	    sed 's/^alias track source.*$$/alias track source ZZZ\/mdb_track/'\
	    > save.out 2>&1

scripts.out: scripts scripts.inp
	EDITOR=cat $(MDB_STD) ./scripts < scripts.inp > scripts.out 2>&1

tabled_read_unitize.out: tabled_read_unitize.data

tabled_typeclass.out: tabled_typeclass tabled_typeclass.inp
	$(MDB_STD) ./tabled_typeclass < tabled_typeclass.inp 2>&1 | \
		sed 's/0x[-0-9A-Fa-f]*/0xXXXX/g' | \
		sed 's/(nil)/0xXXXX/g' | \
		sed 's/stream, [0-9a-fA-F]\{2\}[0-9a-fA-F]*/stream, 0xXXXX/g' | \
		sed 's/system_error, 0\{2\}0*/system_error, 0xXXXX/g' \
		> tabled_typeclass.out 2>&1

# When WORKSPACE is set, use $(WORKSPACE)/tools/lmc to compile the query.
ifneq ($(origin WORKSPACE), undefined)
export WORKSPACE
endif

# Note that interactive.out.orig depends on $(interactive.ints) because
# interactive.inp contains interactive queries that require interactive.ints
# to have been built.
interactive.out.orig: interactive interactive.ints
ifneq ($(origin WORKSPACE),undefined)
	rm -rf lmc
	mkdir ./lmc
	cp $(WORKSPACE)/tools/lmc lmc/mmc
endif
	echo "echo on" > interactive.inp.tmp
	echo mmc_options $(ALL_GRADEFLAGS) $(ALL_MCFLAGS) \
		--trace minimum >> interactive.inp.tmp
	cat interactive.inp >> interactive.inp.tmp
	PATH="`pwd`/lmc:$$PATH" $(MDB) ./interactive \
		< interactive.inp.tmp > interactive.out.orig 2>&1
	rm -f interactive.inp.tmp
	rm -rf lmc

# We pipe the output through sed to avoid differences for `--use-subdirs',
# and to remove some spurious warnings that `gcc' and `ld' issue.
# XXX We should fix the spurious warnings about unresolved symbols.
# (The spurious warnings about exception handling are due to a flaw
# in the Digital Unix 3.2 linker, so that one is DEC's problem.)
# XXX Which is not an issue anymore.
interactive.out: interactive.out.orig
	cat interactive.out.orig | \
		sed \
		    -e '/mdb> mmc_options/d' \
		    -e '/In file included from .*\/lib\/mercury\/inc\/mercury_trace_base.h:[0-9]*,$$/N' \
		    -e 's/In file included from .*\/lib\/mercury\/inc\/mercury_trace_base.h:[0-9]*,.//' \
		    -e '/                 from .*\/lib\/mercury\/inc\/mercury_wrapper.h:[0-9]*,$$/N' \
		    -e 's/                 from .*\/lib\/mercury\/inc\/mercury_wrapper.h:[0-9]*,.//' \
		    -e '/                 from .*\/lib\/mercury\/inc\/mercury_imp.h:[0-9]*,$$/N' \
		    -e 's/                 from .*\/lib\/mercury\/inc\/mercury_imp.h:[0-9]*,.//' \
		    -e '/                 from mdb_query.c:[0-9]*:$$/N' \
		    -e 's/                 from mdb_query.c:[0-9]*:.//' \
		    -e '/                 from .*\/lib\/mercury\/inc\/mercury_library_types.h:[0-9]*,$$/N' \
		    -e 's/                 from .*\/lib\/mercury\/inc\/mercury_library_types.h:[0-9]*,.//' \
		    -e '/                 from .*\/lib\/mercury\/inc\/mercury_imp.h:[0-9]*,$$/N' \
		    -e 's/                 from .*\/lib\/mercury\/inc\/mercury_imp.h:[0-9]*,.//' \
		    -e '/                 from mdb_query.c:[0-9]*:$$/N' \
		    -e 's/                 from mdb_query.c:[0-9]*:.//' \
		    -e '/\/usr\/bin\/ld:$$/N' \
		    -e 's/\/usr\/bin\/ld:.//' \
		    -e '/\/bin\/ld:$$/N' \
		    -e 's/\/bin\/ld:.//' \
		    -e '/Warning: Linking some objects which contain exception information sections$$/N' \
		    -e 's/Warning: Linking some objects which contain exception information sections.//' \
		    -e '/	and some which do not. This may cause fatal runtime exception handling$$/N' \
		    -e 's/	and some which do not. This may cause fatal runtime exception handling.//' \
		    -e '/	problems (last obj encountered without exceptions was .*)\.$$/N' \
		    -e 's/	problems (last obj encountered without exceptions was .*)\..//' \
		    -e '/Warning: Unresolved:$$/N' \
		    -e 's/Warning: Unresolved:.//' \
		    -e '/<predicate .main.\/2 mode 0>$$/N' \
		    -e 's/<predicate .main.\/2 mode 0>.//' \
		    -e '/__start$$/N' \
		    -e 's/__start.//' \
		    > interactive.out
	# ignore egcs internal errors -- those are not our fault
	if grep 'gcc.*Internal compiler error' interactive.out; then \
		cp interactive.exp interactive.out; \
	fi

# We ignore the result of this action because
# the exit status of grep is not useful in this case.
mdb_command_test.out: mdb_command_test mdb_command_test.inp
	-$(MDB) ./mdb_command_test < mdb_command_test.inp 2>&1 \
		| egrep "internal error in the trace help system" \
		> mdb_command_test.out

#---------------------------------------------------------------------------#
