Files
mercury/extras/references/tests/ref_test.m
Warwick Harvey 9cbccbd5dc This change adds a new extras directory, "references".
Estimated hours taken: 70 (plus whatever pets spent when he wrote the
original version of this)

This change adds a new extras directory, "references".  This directory
contains two impure reference type modules and a module that allows scoped
non-backtrackable update, along with examples of using them and tests.
These modules are intended to be useful when HAL is retargetted to Mercury,
for implementing global variables (backtracking and non-backtracking), and
may also be useful for the debugger.

In order to implement these features, a new memory zone "global heap" was
added to the runtime system, for a heap which is not reclaimed on failure,
along with a pair of functions for copying terms to this heap.

runtime/mercury_deep_copy.c:
runtime/mercury_deep_copy.h:
	Added two functions, MR_make_permanent() and
	MR_make_partially_permanent(), which essentially do a deep copy of a
	term to the global heap.
	(In conservative GC grades, these functions actually do nothing).

runtime/mercury_engine.c:
runtime/mercury_engine.h:
	Added fields global_heap_zone and e_global_hp (for the global heap
	and its heap pointer) to the MR_mercury_engine_struct, along with
	appropriate initialisation, etc.
	Defined MR_heap_zone, MR_solutions_heap_zone, and
	MR_global_heap_zone for convenient access to the corresponding field
	of the relevant Mercury engine.

runtime/mercury_memory.c:
	Added code for handling the size and zone size of the global heap.

runtime/mercury_regorder.h:
runtime/mercury_regs.h:
	Defined MR_global_hp (the global heap pointer for general use),
	along with corresponding other changes.

runtime/mercury_wrapper.c:
runtime/mercury_wrapper.h:
	Added declarations and initialisation of the size and zone_size of
	the global_heap.
	Added an entry for MR_GLOBAL_HP_RN to print_register_usage_counts()
	(plus missing entries for MR_SOL_HP_RN, MR_MIN_HP_REC and
	MR_MIN_SOL_HP_REC).

New files:

extras/references/Mmakefile:
	Mmakefile for building and testing these modules.

extras/references/README:
	Description of contents of this directory.

extras/references/global.m:
	A wrapper module for building a library containing the nb_reference,
	reference and scoped_update modules.

extras/references/nb_reference.m:
	Implements references which are not backtracked on failure.

extras/references/reference.m:
	Implements references which *are* backtracked on failure.

extras/references/scoped_update.m:
	Allows nested scoping of non-backtracking references.

extras/references/samples/Mmakefile:
extras/references/samples/max_of.m:
extras/references/samples/max_test.exp:
extras/references/samples/max_test.m:
	An example of using a non-backtracking reference (to find the
	maximum of the solutions generated by a predicate), with tests.

extras/references/tests/Mmakefile:
extras/references/tests/ref_test.exp:
extras/references/tests/ref_test.m:
	Some tests of references (backtracking and non-backtracking) and
	scoping.
1998-06-18 04:30:48 +00:00

147 lines
3.6 KiB
Mathematica

%-----------------------------------------------------------------------------%
% Copyright (C) 1998 University of Melbourne.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%-----------------------------------------------------------------------------%
%
% File : ref_test.m
% Authors : pets (Peter Schachte)
% Purpose : test of reference types
%
:- module ref_test.
:- interface.
:- import_module io.
:- impure pred main(io__state::di, io__state::uo) is det.
:- implementation.
:- import_module int.
:- import_module reference, nb_reference, scoped_update.
main -->
{ impure new_reference(3,X) },
{ impure new_nb_reference(3,Y) },
(
{ impure update(X, 42) },
{ impure update(Y, 42) },
{ semipure value(X,V1) },
{ semipure value(Y,W1) },
print(V1),
nl,
print(W1),
nl,
{same(X, X1)},
{same(Y, Y1)},
{ impure update(X1, 7) },
{ impure update(Y1, 7) },
{ semipure value(X, V2) },
{ semipure value(Y, W2) },
print(V2),
nl,
print(W2),
nl,
{ impure scope_test }
;
{ impure scope_test2 }
;
{ semipure value(X, V3) },
print(V3),
nl,
{ semipure value(Y, W3) },
print(W3),
nl
).
% Here is an example of using references to implement non-backtrackable
% global variables. We implement global variables with a function that
% returns a reference.
:- pragma c_header_code("extern Integer globalvar;").
:- pragma c_code("Integer globalvar = 0;").
:- func globalvar = nb_reference(int).
:- pragma inline(globalvar/0).
:- pragma c_code(globalvar = (Ref::out), will_not_call_mercury, "
Ref = (Word) &globalvar;
").
% Here is an example of using the scoped_update module. This effectively
% creates two versions of globalvar: one between the enter_scope/
% exit_scope pair, and one outside it.
:- impure pred scope_test is failure.
scope_test :-
small_int(I),
semipure value(globalvar, V0),
impure update(globalvar, V0 + I),
impure scope_test_message("before", V0, V0 + I),
impure enter_scope(globalvar, Handle),
small_int(J),
semipure value(globalvar, V1),
impure scope_test_message("inside", V1, V1 + (J * 10)),
impure update(globalvar, V1 + (J * 10)),
impure exit_scope(Handle),
semipure value(globalvar, V2),
impure update(globalvar, V2 + (I * 100)),
impure scope_test_message("after", V2, V2 + (I * 100)),
fail.
% This predicate checks nested enter/exit scope calls.
:- impure pred scope_test2 is failure.
scope_test2 :-
semipure value(globalvar, V0),
impure update(globalvar, 0),
impure scope_test_message("outside", V0, 0),
impure enter_scope(globalvar, Handle1),
semipure value(globalvar, V1),
impure update(globalvar, 1),
impure scope_test_message("inside 1", V1, 1),
impure enter_scope(globalvar, Handle2),
semipure value(globalvar, V2),
impure update(globalvar, 2),
impure scope_test_message("inside 2", V2, 2),
impure exit_scope(Handle2),
semipure value(globalvar, V3),
impure update(globalvar, 3),
impure scope_test_message("inside 1", V3, 3),
impure exit_scope(Handle1),
semipure value(globalvar, V4),
impure update(globalvar, 4),
impure scope_test_message("outside", V4, 4),
fail.
:- pred same(T, T).
:- mode same(in, in) is semidet.
:- mode same(in, out) is det.
:- mode same(out, in) is det.
same(X,X).
:- pred small_int(int::out) is multi.
small_int(1).
small_int(2).
small_int(3).
:- impure pred scope_test_message(string::in, int::in, int::in) is det.
:- pragma c_header_code("
#include <stdio.h>
").
:- pragma c_code(scope_test_message(Prefix::in, Old::in, New::in),
will_not_call_mercury, "
printf(""%s scope ref = %d; reset to %d\n"", (char *) Prefix,
(int) Old, (int) New);
").