Files
mercury/library/std_util.m
Zoltan Somogyi 26caad3050 Remove type_ctor_layouts and type_ctor_functors where not needed.
Estimated hours taken: 8, plus about 12 hours by Tyson.

Remove type_ctor_layouts and type_ctor_functors where not needed.
Simplify type_ctor_layouts by removing code that generates (and
documentations for) particularly representations that are no longer used
now that we use type_ctor_reps.

Several files also had miscellaneous cleanups and documentation fixes,
the most important being the move of the type_ctor_info structures
for preds/funcs from runtime/mercury_type_info.c to library/builtin.m.

compiler/base_type_layout.m:
        Simplify documentation.

        Remove references to representations in type_ctor_layouts that
        are no longer used.compiler/base_type_layout.m:

compiler/base_type_info.m:
	Keep base_type_info__type_ctor_rep_to_int in sync with
	MR_TypeCtorRepresentation.

runtime/mercury_grade.h:
runtime/mercury_cpp.h:
	Move the definitions of MR_STRINGIFY and MR_PASTEn to the new file
	mercury_cpp.h. Add MR_PASTEn for several new values of n, for use by
	mercury_type_info.h.

runtime/mercury_type_info.h:
	Define macros for creating type_ctor_info structures for builtin types.
	These have NULL layout and functor fields.

	Remove several obsolete macros.

runtime/mercury_layout_util.c:
	Use the new macros for defining a dummy type_ctor_info.

runtime/mercury_deep_copy_body.h:
runtime/mercury_tabling.c:
	Modify the implementation of some RTTI functions to use the layout
	and functors structures only if they are defined.

runtime/mercury_type_info.c:
	Modify MR_collapse_equivalences to use the type_ctor_rep, not the
	functors indicator, to check for equivalence, since the latter is
	not guaranteed to be present.

	Move the type_ctor_info structure for preds/funcs to builtin.m.

library/array.m:
	Use these macros to define the type_ctor_info structure for array.

library/builtin.m:
	Use these macros to define the type_ctor_info structure for int,
	float, character, string, saved succip etc values, and for preds
	and funcs.

library/private_builtin.m:
	Use these macros to define the type_ctor_info structure for type_infos,
	type_ctor_infos, typeclass_infos and base_typeclass_infos.

	Move a c_header_code to the section that needs it.

library/std_util.m:
	Use the new macros to define the type_ctor_info structure for univ
	and for std_util's own type_info type.

	Modify the implementations of some RTTI predicates to use the
	layout and functors structures only if they are defined.
2000-01-19 09:45:23 +00:00

2816 lines
85 KiB
Mathematica

%-----------------------------------------------------------------------------%
% Copyright (C) 1994-2000 The University of Melbourne.
% This file may only be copied under the terms of the GNU Library General
% Public License - see the file COPYING.LIB in the Mercury distribution.
%-----------------------------------------------------------------------------%
% File: std_util.m.
% Main author: fjh.
% Stability: medium to high.
% This file is intended for all the useful standard utilities
% that don't belong elsewhere, like <stdlib.h> in C.
% Ralph Becket <rwab1@cam.sri.com> 24/04/99
% Function forms added.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- module std_util.
:- interface.
:- import_module list, set, bool.
%-----------------------------------------------------------------------------%
% The universal type `univ'.
% An object of type `univ' can hold the type and value of an object of any
% other type.
:- type univ.
% type_to_univ(Object, Univ):
% true iff the type stored in `Univ' is the same as the type
% of `Object', and the value stored in `Univ' is equal to the
% value of `Object'.
%
% Operational, the forwards mode converts an object to type `univ',
% while the reverse mode converts the value stored in `Univ'
% to the type of `Object', but fails if the type stored in `Univ'
% does not match the type of `Object'.
%
:- pred type_to_univ(T, univ).
:- mode type_to_univ(di, uo) is det.
:- mode type_to_univ(in, out) is det.
:- mode type_to_univ(out, in) is semidet.
% univ_to_type(Univ, Object) :- type_to_univ(Object, Univ).
%
:- pred univ_to_type(univ, T).
:- mode univ_to_type(in, out) is semidet.
:- mode univ_to_type(out, in) is det.
:- mode univ_to_type(uo, di) is det.
% The function univ/1 provides the same
% functionality as type_to_univ/2.
% univ(Object) = Univ :- type_to_univ(Object, Univ).
%
:- func univ(T) = univ.
:- mode univ(in) = out is det.
:- mode univ(di) = uo is det.
:- mode univ(out) = in is semidet.
% det_univ_to_type(Univ, Object):
% the same as the forwards mode of univ_to_type, but
% abort if univ_to_type fails.
%
:- pred det_univ_to_type(univ, T).
:- mode det_univ_to_type(in, out) is det.
% univ_type(Univ):
% returns the type_info for the type stored in `Univ'.
%
:- func univ_type(univ) = type_info.
% univ_value(Univ):
% returns the value of the object stored in Univ.
:- some [T] func univ_value(univ) = T.
%-----------------------------------------------------------------------------%
% The "maybe" type.
:- type maybe(T) ---> no ; yes(T).
:- type maybe_error ---> ok ; error(string).
:- type maybe_error(T) ---> ok(T) ; error(string).
%-----------------------------------------------------------------------------%
% The "unit" type - stores no information at all.
:- type unit ---> unit.
%-----------------------------------------------------------------------------%
% The "pair" type. Useful for many purposes.
:- type pair(T1, T2) ---> (T1 - T2).
:- type pair(T) == pair(T,T).
% Return the first element of the pair.
:- pred fst(pair(X,Y)::in, X::out) is det.
:- func fst(pair(X,Y)) = X.
% Return the second element of the pair.
:- pred snd(pair(X,Y)::in, Y::out) is det.
:- func snd(pair(X,Y)) = Y.
%-----------------------------------------------------------------------------%
% solutions/2 collects all the solutions to a predicate and
% returns them as a list in sorted order, with duplicates removed.
% solutions_set/2 returns them as a set.
% unsorted_solutions/2 returns them as an unsorted list with possible
% duplicates; since there are an infinite number of such lists,
% this must be called from a context in which only a single solution
% is required.
:- pred solutions(pred(T), list(T)).
:- mode solutions(pred(out) is multi, out) is det.
:- mode solutions(pred(out) is nondet, out) is det.
:- pred solutions_set(pred(T), set(T)).
:- mode solutions_set(pred(out) is multi, out) is det.
:- mode solutions_set(pred(out) is nondet, out) is det.
:- pred unsorted_solutions(pred(T), list(T)).
:- mode unsorted_solutions(pred(out) is multi, out) is cc_multi.
:- mode unsorted_solutions(pred(out) is nondet, out) is cc_multi.
%-----------------------------------------------------------------------------%
% aggregate/4 generates all the solutions to a predicate,
% sorts them and removes duplicates, then applies an accumulator
% predicate to each solution in turn:
%
% aggregate(Generator, Accumulator, Acc0, Acc) <=>
% solutions(Generator, Solutions),
% list__foldl(Accumulator, Solutions, Acc0, Acc).
%
:- pred aggregate(pred(T), pred(T, U, U), U, U).
:- mode aggregate(pred(out) is multi, pred(in, in, out) is det,
in, out) is det.
:- mode aggregate(pred(out) is multi, pred(in, di, uo) is det,
di, uo) is det.
:- mode aggregate(pred(out) is nondet, pred(in, di, uo) is det,
di, uo) is det.
:- mode aggregate(pred(out) is nondet, pred(in, in, out) is det,
in, out) is det.
% unsorted_aggregate/4 generates all the solutions to a predicate
% and applies an accumulator predicate to each solution in turn.
% Declaratively, the specification is as follows:
%
% unsorted_aggregate(Generator, Accumulator, Acc0, Acc) <=>
% unsorted_solutions(Generator, Solutions),
% list__foldl(Accumulator, Solutions, Acc0, Acc).
%
% Operationally, however, unsorted_aggregate/4 will call the
% Accumulator for each solution as it is obtained, rather than
% first building a list of all the solutions.
:- pred unsorted_aggregate(pred(T), pred(T, U, U), U, U).
:- mode unsorted_aggregate(pred(out) is multi, pred(in, in, out) is det,
in, out) is cc_multi.
:- mode unsorted_aggregate(pred(out) is multi, pred(in, di, uo) is det,
di, uo) is cc_multi.
:- mode unsorted_aggregate(pred(muo) is multi, pred(mdi, di, uo) is det,
di, uo) is cc_multi.
:- mode unsorted_aggregate(pred(out) is nondet, pred(in, di, uo) is det,
di, uo) is cc_multi.
:- mode unsorted_aggregate(pred(out) is nondet, pred(in, in, out) is det,
in, out) is cc_multi.
:- mode unsorted_aggregate(pred(muo) is nondet, pred(mdi, di, uo) is det,
di, uo) is cc_multi.
% This is a generalization of unsorted_aggregate which allows the
% iteration to stop before all solutions have been found.
% Declaratively, the specification is as follows:
%
% do_while(Generator, Filter) -->
% { unsorted_solutions(Generator, Solutions) },
% do_while_2(Solutions, Filter).
%
% do_while_2([], _) --> [].
% do_while_2([X|Xs], Filter) -->
% Filter(X, More),
% (if { More = yes } then
% do_while_2(Xs, Filter)
% else
% { true }
% ).
%
% Operationally, however, do_while/4 will call the Filter
% predicate for each solution as it is obtained, rather than
% first building a list of all the solutions.
%
:- pred do_while(pred(T), pred(T, bool, T2, T2), T2, T2).
:- mode do_while(pred(out) is multi, pred(in, out, in, out) is det, in, out)
is cc_multi.
:- mode do_while(pred(out) is nondet, pred(in, out, in, out) is det, in, out)
is cc_multi.
:- mode do_while(pred(out) is multi, pred(in, out, di, uo) is det, di, uo)
is cc_multi.
:- mode do_while(pred(out) is nondet, pred(in, out, di, uo) is det, di, uo)
is cc_multi.
%-----------------------------------------------------------------------------%
% maybe_pred(Pred, X, Y) takes a closure Pred which transforms an
% input semideterministically. If calling the closure with the input
% X succeeds, Y is bound to `yes(Z)' where Z is the output of the
% call, or to `no' if the call fails.
%
:- pred maybe_pred(pred(T1, T2), T1, maybe(T2)).
:- mode maybe_pred(pred(in, out) is semidet, in, out) is det.
%-----------------------------------------------------------------------------%
% `semidet_succeed' is exactly the same as `true', except that
% the compiler thinks that it is semi-deterministic. You can
% use calls to `semidet_succeed' to suppress warnings about
% determinism declarations which could be stricter.
% Similarly, `semidet_fail' is like `fail' except that its
% determinism is semidet rather than failure, and
% `cc_multi_equal(X,Y)' is the same as `X=Y' except that it
% is cc_multi rather than det.
:- pred semidet_succeed is semidet.
:- pred semidet_fail is semidet.
:- pred cc_multi_equal(T, T).
:- mode cc_multi_equal(di, uo) is cc_multi.
:- mode cc_multi_equal(in, out) is cc_multi.
%-----------------------------------------------------------------------------%
% The `type_info' and `type_ctor_info' types: these
% provide access to type information.
% A type_info represents a type, e.g. `list(int)'.
% A type_ctor_info represents a type constructor, e.g. `list/1'.
:- type type_info.
:- type type_ctor_info.
% (Note: it is not possible for the type of a variable to be an
% unbound type variable; if there are no constraints on a type
% variable, then the typechecker will use the type `void'.
% `void' is a special (builtin) type that has no constructors.
% There is no way of creating an object of type `void'.
% `void' is not considered to be a discriminated union, so
% get_functor/5 and construct/3 will fail if used upon a value
% of this type.)
% The function type_of/1 returns a representation of the type
% of its argument.
%
:- func type_of(T) = type_info.
:- mode type_of(unused) = out is det.
% The predicate has_type/2 is basically an existentially typed
% inverse to the function type_of/1. It constrains the type
% of the first argument to be the type represented by the
% second argument.
:- some [T] pred has_type(T::unused, type_info::in) is det.
% type_name(Type) returns the name of the specified type
% (e.g. type_name(type_of([2,3])) = "list:list(int)").
% Any equivalence types will be fully expanded.
% Builtin types (those defined in builtin.m) will
% not have a module qualifier.
%
:- func type_name(type_info) = string.
% type_ctor_and_args(Type, TypeCtor, TypeArgs):
% True iff `TypeCtor' is a representation of the top-level
% type constructor for `Type', and `TypeArgs' is a list
% of the corresponding type arguments to `TypeCtor',
% and `TypeCtor' is not an equivalence type.
%
% For example, type_ctor_and_args(type_of([2,3]), TypeCtor,
% TypeArgs) will bind `TypeCtor' to a representation of the
% type constructor list/1, and will bind `TypeArgs' to the list
% `[Int]', where `Int' is a representation of the type `int'.
%
% Note that the requirement that `TypeCtor' not be an
% equivalence type is fulfilled by fully expanding any
% equivalence types. For example, if you have a declaration
% `:- type foo == bar.', then type_ctor_and_args/3 will always
% return a representation of type constructor `bar/0', not `foo/0'.
% (If you don't want them expanded, you can use the reverse mode
% of make_type/2 instead.)
%
:- pred type_ctor_and_args(type_info, type_ctor_info, list(type_info)).
:- mode type_ctor_and_args(in, out, out) is det.
% type_ctor(Type) = TypeCtor :-
% type_ctor_and_args(Type, TypeCtor, _).
%
:- func type_ctor(type_info) = type_ctor_info.
% type_args(Type) = TypeArgs :-
% type_ctor_and_args(Type, _, TypeArgs).
%
:- func type_args(type_info) = list(type_info).
% type_ctor_name(TypeCtor) returns the name of specified
% type constructor.
% (e.g. type_ctor_name(type_ctor(type_of([2,3]))) = "list").
%
:- func type_ctor_name(type_ctor_info) = string.
% type_ctor_module_name(TypeCtor) returns the module name of specified
% type constructor.
% (e.g. type_ctor_module_name(type_ctor(type_of(2))) = "builtin").
%
:- func type_ctor_module_name(type_ctor_info) = string.
% type_ctor_arity(TypeCtor) returns the arity of specified
% type constructor.
% (e.g. type_ctor_arity(type_ctor(type_of([2,3]))) = 1).
%
:- func type_ctor_arity(type_ctor_info) = int.
% type_ctor_name_and_arity(TypeCtor, ModuleName, TypeName, Arity) :-
% Name = type_ctor_name(TypeCtor),
% ModuleName = type_ctor_module_name(TypeCtor),
% Arity = type_ctor_arity(TypeCtor).
%
:- pred type_ctor_name_and_arity(type_ctor_info, string, string, int).
:- mode type_ctor_name_and_arity(in, out, out, out) is det.
% make_type(TypeCtor, TypeArgs) = Type:
% True iff `Type' is a type constructed by applying
% the type constructor `TypeCtor' to the type arguments
% `TypeArgs'.
%
% Operationally, the forwards mode returns the type formed by
% applying the specified type constructor to the specified
% argument types, or fails if the length of TypeArgs is not the
% same as the arity of TypeCtor. The reverse mode returns a
% type constructor and its argument types, given a type_info;
% the type constructor returned may be an equivalence type
% (and hence this reverse mode of make_type/2 may be more useful
% for some purposes than the type_ctor/1 function).
%
:- func make_type(type_ctor_info, list(type_info)) = type_info.
:- mode make_type(in, in) = out is semidet.
:- mode make_type(out, out) = in is cc_multi.
% det_make_type(TypeCtor, TypeArgs):
%
% Returns the type formed by applying the specified type
% constructor to the specified argument types. Aborts if the
% length of `TypeArgs' is not the same as the arity of `TypeCtor'.
%
:- func det_make_type(type_ctor_info, list(type_info)) = type_info.
:- mode det_make_type(in, in) = out is det.
%-----------------------------------------------------------------------------%
% num_functors(TypeInfo)
%
% Returns the number of different functors for the top-level
% type constructor of the type specified by TypeInfo, or -1
% if the type is not a discriminated union type.
%
:- func num_functors(type_info) = int.
% get_functor(Type, N, Functor, Arity, ArgTypes)
%
% Binds Functor and Arity to the name and arity of the Nth
% functor for the specified type (starting at zero), and binds
% ArgTypes to the type_infos for the types of the arguments of
% that functor. Fails if the type is not a discriminated union
% type, or if N is out of range.
%
:- pred get_functor(type_info::in, int::in, string::out, int::out,
list(type_info)::out) is semidet.
% construct(TypeInfo, N, Args) = Term
%
% Returns a term of the type specified by TypeInfo whose functor
% is the Nth functor of TypeInfo (starting at zero), and whose
% arguments are given by Args. Fails if the type is not a
% discriminated union type, or if N is out of range, or if the
% number of arguments doesn't match the arity of the Nth functor
% of the type, or if the types of the arguments doesn't match
% the expected argument types for that functor.
%
:- func construct(type_info, int, list(univ)) = univ.
:- mode construct(in, in, in) = out is semidet.
%-----------------------------------------------------------------------------%
% functor, argument and deconstruct take any type (including univ),
% and return representation information for that type.
%
% The string representation of the functor that `functor' and
% `deconstruct' return is:
% - for user defined types, the functor that is given
% in the type definition. For lists, this
% means the functors ./2 and []/0 are used, even if
% the list uses the [....] shorthand.
% - for integers, the string is a base 10 number,
% positive integers have no sign.
% - for floats, the string is a floating point,
% base 10 number, positive floating point numbers have
% no sign.
% - for strings, the string, inside double quotation marks
% - for characters, the character inside single
% quotation marks
% - for predicates and functions, the string
% <<predicate>>
% functor(Data, Functor, Arity)
%
% Given a data item (Data), binds Functor to a string
% representation of the functor and Arity to the arity of this
% data item. (Aborts if the type of Data is a type with a
% non-canonical representation, i.e. one for which there is a
% user-defined equality predicate.)
%
:- pred functor(T::in, string::out, int::out) is det.
% arg(Data, ArgumentIndex) = Argument
% argument(Data, ArgumentIndex) = ArgumentUniv
%
% Given a data item (Data) and an argument index
% (ArgumentIndex), starting at 0 for the first argument, binds
% Argument to that argument of the functor of the data item. If
% the argument index is out of range -- that is, greater than or
% equal to the arity of the functor or lower than 0 -- then
% the call fails. For argument/1 the argument returned has the
% type univ, which can store any type. For arg/1, if the
% argument has the wrong type, then the call fails.
% (Both abort if the type of Data is a type with a non-canonical
% representation, i.e. one for which there is a user-defined
% equality predicate.)
%
:- func arg(T::in, int::in) = (ArgT::out) is semidet.
:- func argument(T::in, int::in) = (univ::out) is semidet.
% det_arg(Data, ArgumentIndex) = Argument
% det_argument(Data, ArgumentIndex) = ArgumentUniv
%
% Same as arg/2 and argument/2 respectively, except that
% for cases where arg/2 or argument/2 would fail,
% det_arg/2 or det_argument/2 will abort.
%
:- func det_arg(T::in, int::in) = (ArgT::out) is det.
:- func det_argument(T::in, int::in) = (univ::out) is det.
% deconstruct(Data, Functor, Arity, Arguments)
%
% Given a data item (Data), binds Functor to a string
% representation of the functor, Arity to the arity of this data
% item, and Arguments to a list of arguments of the functor.
% The arguments in the list are each of type univ.
% (Aborts if the type of Data is a type with a non-canonical
% representation, i.e. one for which there is a user-defined
% equality predicate.)
%
:- pred deconstruct(T::in, string::out, int::out, list(univ)::out) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module require, set, int, string, bool.
%-----------------------------------------------------------------------------%
/****
Is this really useful?
% for use in lambda expressions where the type of functor '-' is ambiguous
:- pred pair(X, Y, pair(X, Y)).
:- mode pair(in, in, out) is det.
:- mode pair(out, out, in) is det.
pair(X, Y, X-Y).
****/
fst(X-_Y) = X.
fst(P,X) :-
X = fst(P).
snd(_X-Y) = Y.
snd(P,X) :-
X = snd(P).
maybe_pred(Pred, X, Y) :-
(
call(Pred, X, Z)
->
Y = yes(Z)
;
Y = no
).
%-----------------------------------------------------------------------------%
/*
** This section defines builtin_aggregate/4 which takes a closure of type
** pred(T) in which the remaining argument is output, and backtracks over
** solutions for this, using the second argument to aggregate them however the
** user wishes. This is basically a generalization of solutions/2.
*/
:- pred builtin_aggregate(pred(T), pred(T, U, U), U, U).
:- mode builtin_aggregate(pred(out) is multi, pred(in, in, out) is det,
in, out) is det. /* really cc_multi */
:- mode builtin_aggregate(pred(out) is multi, pred(in, di, uo) is det,
di, uo) is det. /* really cc_multi */
:- mode builtin_aggregate(pred(muo) is multi, pred(mdi, di, uo) is det,
di, uo) is det. /* really cc_multi */
:- mode builtin_aggregate(pred(out) is nondet, pred(in, di, uo) is det,
di, uo) is det. /* really cc_multi */
:- mode builtin_aggregate(pred(out) is nondet, pred(in, in, out) is det,
in, out) is det. /* really cc_multi */
:- mode builtin_aggregate(pred(muo) is nondet, pred(mdi, di, uo) is det,
di, uo) is det. /* really cc_multi */
/*
** In order to implement any sort of code that requires terms to survive
** backtracking, we need to (deeply) copy them out of the heap and into some
** other area before backtracking. The obvious thing to do then is just call
** the generator predicate, let it run to completion, and copy its result into
** another memory area (call it the solutions heap) before forcing
** backtracking. When we get the next solution, we do the same, this time
** passing the previous collection (which is still on the solutions heap) to
** the collector predicate. If the result of this operation contains the old
** collection as a part, then the deep copy operation is smart enough
** not to copy again. So this could be pretty efficient.
**
** But what if the collector predicate does something that copies the previous
** collection? Then on each solution, we'll copy the previous collection to
** the heap, and then deep copy it back to the solution heap. This means
** copying solutions order N**2 times, where N is the number of solutions. So
** this isn't as efficient as we hoped.
**
** So we use a slightly different approach. When we find a solution, we deep
** copy it to the solution heap. Then, before calling the collector code, we
** sneakily swap the runtime system's notion of which is the heap and which is
** the solutions heap. This ensures that any terms are constructed on the
** solutions heap. When this is complete, we swap them back, and force the
** engine to backtrack to get the next solution. And so on. After we've
** gotten the last solution, we do another deep copy to move the solution back
** to the 'real' heap, and reset the solutions heap pointer (which of course
** reclaims all the garbage of the collection process).
**
** Note that this will work with recursive calls to builtin_aggregate as
** well. If the recursive invocation occurs in the generator pred, there can
** be no problem because by the time the generator succeeds, the inner
** do_ call will have completed, copied its result from the solutions heap,
** and reset the solutions heap pointer. If the recursive invocation happens
** in the collector pred, then it will happen when the heap and solutions heap
** are 'swapped.' This will work out fine, because the real heap isn't needed
** while the collector pred is executing, and by the time the nested do_ is
** completed, the 'real' heap pointer will have been reset.
**
** If the collector predicate throws an exception while they are swapped,
** then the code for builtin_throw/1 will unswap the heaps.
** So we don't need to create our own exception handlers to here to
** cover that case.
**
** If we're using conservative GC, then all of the heap-swapping
** and copying operations are no-ops, so we get a "zero-copy" solution.
*/
% Note that the code for builtin_aggregate is very similar to the code
% for do_while (below).
:- pragma promise_pure(builtin_aggregate/4).
builtin_aggregate(GeneratorPred, CollectorPred, Accumulator0, Accumulator) :-
% Save some of the Mercury virtual machine registers
impure get_registers(HeapPtr, SolutionsHeapPtr, TrailPtr),
% Initialize the accumulator
% /* Mutvar := Accumulator0 */
impure new_mutvar(Accumulator0, Mutvar),
(
% Get a solution
GeneratorPred(Answer0),
% Check that the generator didn't leave any
% delayed goals outstanding
impure check_for_floundering(TrailPtr),
% Update the accumulator
% /* MutVar := CollectorPred(MutVar) */
impure swap_heap_and_solutions_heap,
impure partial_deep_copy(HeapPtr, Answer0, Answer),
impure get_mutvar(Mutvar, Acc0),
CollectorPred(Answer, Acc0, Acc1),
impure set_mutvar(Mutvar, Acc1),
impure swap_heap_and_solutions_heap,
% Force backtracking, so that we get the next solution.
% This will automatically reset the heap and trail.
fail
;
% There are no more solutions.
% So now we just need to copy the final value
% of the accumulator from the solutions heap
% back onto the ordinary heap, and then we can
% reset the solutions heap pointer.
% /* Accumulator := MutVar */
impure get_mutvar(Mutvar, Accumulator1),
impure partial_deep_copy(SolutionsHeapPtr, Accumulator1,
Accumulator),
impure reset_solutions_heap(SolutionsHeapPtr)
).
% The code for do_while/4 is essentially the same as the code for
% builtin_aggregate (above). See the detailed comments above.
%
% XXX It would be nice to avoid the code duplication here,
% but it is a bit tricky -- we can't just use a lambda expression,
% because we'd need to specify the mode, but we want it to work
% for multiple modes. An alternative would be to use a typeclass,
% but typeclasses still don't work in `jump' or `fast' grades.
:- pragma promise_pure(do_while/4).
do_while(GeneratorPred, CollectorPred, Accumulator0, Accumulator) :-
impure get_registers(HeapPtr, SolutionsHeapPtr, TrailPtr),
impure new_mutvar(Accumulator0, Mutvar),
(
GeneratorPred(Answer0),
impure check_for_floundering(TrailPtr),
impure swap_heap_and_solutions_heap,
impure partial_deep_copy(HeapPtr, Answer0, Answer),
impure get_mutvar(Mutvar, Acc0),
CollectorPred(Answer, More, Acc0, Acc1),
impure set_mutvar(Mutvar, Acc1),
impure swap_heap_and_solutions_heap,
% if More = yes, then backtrack for the next solution.
% if More = no, then we're done.
More = no
;
true
),
impure get_mutvar(Mutvar, Accumulator1),
impure partial_deep_copy(SolutionsHeapPtr, Accumulator1, Accumulator),
impure reset_solutions_heap(SolutionsHeapPtr).
:- type heap_ptr ---> heap_ptr(c_pointer).
:- type trail_ptr ---> trail_ptr(c_pointer).
%
% Save the state of the Mercury heap and trail registers,
% for later use in partial_deep_copy/3 and reset_solutions_heap/1.
%
:- impure pred get_registers(heap_ptr::out, heap_ptr::out, trail_ptr::out)
is det.
:- pragma c_code(get_registers(HeapPtr::out, SolutionsHeapPtr::out,
TrailPtr::out), will_not_call_mercury,
"
/* save heap states */
#ifndef CONSERVATIVE_GC
HeapPtr = MR_hp;
SolutionsHeapPtr = MR_sol_hp;
#else
HeapPtr = SolutionsHeapPtr = 0;
#endif
/* save trail state */
#ifdef MR_USE_TRAIL
MR_store_ticket(TrailPtr);
#else
TrailPtr = 0;
#endif
").
:- impure pred check_for_floundering(trail_ptr::in) is det.
:- pragma c_code(check_for_floundering(TrailPtr::in), [will_not_call_mercury],
"
#ifdef MR_USE_TRAIL
/* check for outstanding delayed goals (``floundering'') */
MR_reset_ticket(TrailPtr, MR_solve);
#endif
").
%
% Swap the heap with the solutions heap
%
:- impure pred swap_heap_and_solutions_heap is det.
:- pragma c_code(swap_heap_and_solutions_heap,
will_not_call_mercury,
"
#ifndef CONSERVATIVE_GC
{
MemoryZone *temp_zone;
Word *temp_hp;
temp_zone = MR_ENGINE(heap_zone);
MR_ENGINE(heap_zone) = MR_ENGINE(solutions_heap_zone);
MR_ENGINE(solutions_heap_zone) = temp_zone;
temp_hp = MR_hp;
MR_hp = MR_sol_hp;
MR_sol_hp = temp_hp;
}
#endif
").
%
% partial_deep_copy(SolutionsHeapPtr, OldVal, NewVal):
% Make a copy of all of the parts of OldVar that occur between
% SolutionsHeapPtr and the top of the current solutions heap.
%
:- impure pred partial_deep_copy(heap_ptr, T, T) is det.
:- mode partial_deep_copy(in, di, uo) is det.
:- mode partial_deep_copy(in, mdi, muo) is det.
:- mode partial_deep_copy(in, in, out) is det.
:- pragma c_header_code("
#include ""mercury_deep_copy.h""
#ifdef CONSERVATIVE_GC
/* for conservative GC, shallow copies suffice */
#define MR_PARTIAL_DEEP_COPY(SolutionsHeapPtr, \\
OldVar, NewVal, TypeInfo_for_T) \\
do { \\
NewVal = OldVal; \\
} while (0)
#else
/*
** Note that we need to save/restore the MR_hp register, if it
** is transient, before/after calling deep_copy().
*/
#define MR_PARTIAL_DEEP_COPY(SolutionsHeapPtr, \\
OldVar, NewVal, TypeInfo_for_T) \\
do { \\
save_transient_hp(); \\
NewVal = deep_copy(&OldVal, TypeInfo_for_T, \\
SolutionsHeapPtr, \\
MR_ENGINE(solutions_heap_zone)->top); \\
restore_transient_hp(); \\
} while (0)
#endif
").
:- pragma c_code(partial_deep_copy(SolutionsHeapPtr::in,
OldVal::in, NewVal::out), will_not_call_mercury,
"
MR_PARTIAL_DEEP_COPY(SolutionsHeapPtr, OldVal, NewVal, TypeInfo_for_T);
").
:- pragma c_code(partial_deep_copy(SolutionsHeapPtr::in,
OldVal::mdi, NewVal::muo), will_not_call_mercury,
"
MR_PARTIAL_DEEP_COPY(SolutionsHeapPtr, OldVal, NewVal, TypeInfo_for_T);
").
:- pragma c_code(partial_deep_copy(SolutionsHeapPtr::in,
OldVal::di, NewVal::uo), will_not_call_mercury,
"
MR_PARTIAL_DEEP_COPY(SolutionsHeapPtr, OldVal, NewVal, TypeInfo_for_T);
").
%
% reset_solutions_heap(SolutionsHeapPtr):
% Reset the solutions heap pointer to the specified value,
% thus deallocating everything allocated on the solutions
% heap since that value was obtained via get_registers/3.
%
:- impure pred reset_solutions_heap(heap_ptr::in) is det.
:- pragma c_code(reset_solutions_heap(SolutionsHeapPtr::in),
will_not_call_mercury,
"
#ifndef CONSERVATIVE_GC
MR_sol_hp = SolutionsHeapPtr;
#endif
").
%-----------------------------------------------------------------------------%
%%% :- module mutvar.
%%% :- interface.
% A non-backtrackably destructively modifiable reference type
:- type mutvar(T).
% Create a new mutvar given a term for it to reference.
:- impure pred new_mutvar(T, mutvar(T)).
:- mode new_mutvar(in, out) is det.
:- mode new_mutvar(di, uo) is det.
% Get the value currently referred to by a reference.
:- impure pred get_mutvar(mutvar(T), T) is det.
:- mode get_mutvar(in, uo) is det. % XXX this is a work-around
/*
XXX `ui' modes don't work yet
:- mode get_mutvar(in, uo) is det.
:- mode get_mutvar(ui, uo) is det. % unsafe, but we use it safely
*/
% destructively modify a reference to refer to a new object.
:- impure pred set_mutvar(mutvar(T), T) is det.
:- mode set_mutvar(in, in) is det.
/*
XXX `ui' modes don't work yet
:- pred set_mutvar(ui, di) is det.
*/
%%% :- implementation.
% This type is implemented in C.
:- type mutvar(T) ---> mutvar(c_pointer).
:- pragma inline(new_mutvar/2).
:- pragma c_code(new_mutvar(X::in, Ref::out), will_not_call_mercury,
"
incr_hp_msg(Ref, 1, MR_PROC_LABEL, ""std_util:mutvar/1"");
*(Word *) Ref = X;
").
:- pragma c_code(new_mutvar(X::di, Ref::uo), will_not_call_mercury,
"
incr_hp_msg(Ref, 1, MR_PROC_LABEL, ""std_util:mutvar/1"");
*(Word *) Ref = X;
").
:- pragma inline(get_mutvar/2).
:- pragma c_code(get_mutvar(Ref::in, X::uo), will_not_call_mercury,
"
X = *(Word *) Ref;
").
:- pragma inline(set_mutvar/2).
:- pragma c_code(set_mutvar(Ref::in, X::in), will_not_call_mercury, "
*(Word *) Ref = X;
").
%%% end_module mutvar.
%-----------------------------------------------------------------------------%
solutions(Pred, List) :-
builtin_solutions(Pred, UnsortedList),
list__sort_and_remove_dups(UnsortedList, List).
solutions_set(Pred, Set) :-
builtin_solutions(Pred, List),
set__list_to_set(List, Set).
unsorted_solutions(Pred, List) :-
builtin_solutions(Pred, UnsortedList),
cc_multi_equal(UnsortedList, List).
:- pred builtin_solutions(pred(T), list(T)).
:- mode builtin_solutions(pred(out) is multi, out)
is det. /* really cc_multi */
:- mode builtin_solutions(pred(out) is nondet, out)
is det. /* really cc_multi */
builtin_solutions(Generator, UnsortedList) :-
builtin_aggregate(Generator, cons, [], UnsortedList).
:- pred cons(T::in, list(T)::in, list(T)::out) is det.
cons(H, T, [H|T]).
%-----------------------------------------------------------------------------%
aggregate(Generator, Accumulator, Acc0, Acc) :-
solutions(Generator, Solutions),
list__foldl(Accumulator, Solutions, Acc0, Acc).
unsorted_aggregate(Generator, Accumulator, Acc0, Acc) :-
builtin_aggregate(Generator, Accumulator, Acc0, Acc1),
cc_multi_equal(Acc1, Acc).
%-----------------------------------------------------------------------------%
% semidet_succeed and semidet_fail, implemented using the C interface
% to make sure that the compiler doesn't issue any determinism warnings
% for them.
:- pragma c_code(semidet_succeed, [will_not_call_mercury, thread_safe],
"SUCCESS_INDICATOR = TRUE;").
:- pragma c_code(semidet_fail, [will_not_call_mercury, thread_safe],
"SUCCESS_INDICATOR = FALSE;").
:- pragma c_code(cc_multi_equal(X::in, Y::out),
[will_not_call_mercury, thread_safe],
"Y = X;").
:- pragma c_code(cc_multi_equal(X::di, Y::uo),
[will_not_call_mercury, thread_safe],
"Y = X;").
%-----------------------------------------------------------------------------%
% The type `std_util:type_info/0' happens to use much the same
% representation as `private_builtin:type_info/1'.
univ_to_type(Univ, X) :- type_to_univ(X, Univ).
univ(X) = Univ :- type_to_univ(X, Univ).
det_univ_to_type(Univ, X) :-
( type_to_univ(X0, Univ) ->
X = X0
;
UnivTypeName = type_name(univ_type(Univ)),
ObjectTypeName = type_name(type_of(X)),
string__append_list(["det_univ_to_type: conversion failed\\n",
"\tUniv Type: ", UnivTypeName,
"\\n\tObject Type: ", ObjectTypeName], ErrorString),
error(ErrorString)
).
:- pragma c_code(univ_value(Univ::in) = (Value::out), will_not_call_mercury, "
TypeInfo_for_T = MR_field(MR_mktag(0), Univ, UNIV_OFFSET_FOR_TYPEINFO);
Value = MR_field(MR_mktag(0), Univ, UNIV_OFFSET_FOR_DATA);
").
:- pragma c_header_code("
/*
** `univ' is represented as a two word structure.
** One word contains the address of a type_info for the type.
** The other word contains the data.
** The offsets UNIV_OFFSET_FOR_TYPEINFO and UNIV_OFFSET_FOR_DATA
** are defined in runtime/type_info.h.
*/
#include ""mercury_type_info.h""
").
% :- pred type_to_univ(T, univ).
% :- mode type_to_univ(di, uo) is det.
% :- mode type_to_univ(in, out) is det.
% :- mode type_to_univ(out, in) is semidet.
% Forward mode - convert from type to univ.
% Allocate heap space, set the first field to contain the address
% of the type_info for this type, and then store the input argument
% in the second field.
:- pragma c_code(type_to_univ(Type::di, Univ::uo), will_not_call_mercury, "
incr_hp_msg(Univ, 2, MR_PROC_LABEL, ""std_util:univ/0"");
MR_field(MR_mktag(0), Univ, UNIV_OFFSET_FOR_TYPEINFO)
= (Word) TypeInfo_for_T;
MR_field(MR_mktag(0), Univ, UNIV_OFFSET_FOR_DATA)
= (Word) Type;
").
:- pragma c_code(type_to_univ(Type::in, Univ::out), will_not_call_mercury, "
incr_hp_msg(Univ, 2, MR_PROC_LABEL, ""std_util:univ/0"");
MR_field(MR_mktag(0), Univ, UNIV_OFFSET_FOR_TYPEINFO)
= (Word) TypeInfo_for_T;
MR_field(MR_mktag(0), Univ, UNIV_OFFSET_FOR_DATA)
= (Word) Type;
").
% Backward mode - convert from univ to type.
% We check that type_infos compare equal.
% The variable `TypeInfo_for_T' used in the C code
% is the compiler-introduced type-info variable.
:- pragma c_code(type_to_univ(Type::out, Univ::in), will_not_call_mercury, "{
Word univ_type_info;
int comp;
univ_type_info = MR_field(MR_mktag(0), Univ, UNIV_OFFSET_FOR_TYPEINFO);
save_transient_registers();
comp = MR_compare_type_info(univ_type_info, TypeInfo_for_T);
restore_transient_registers();
if (comp == MR_COMPARE_EQUAL) {
Type = MR_field(MR_mktag(0), Univ, UNIV_OFFSET_FOR_DATA);
SUCCESS_INDICATOR = TRUE;
} else {
SUCCESS_INDICATOR = FALSE;
}
}").
:- pragma c_code(univ_type(Univ::in) = (TypeInfo::out), will_not_call_mercury, "
TypeInfo = MR_field(MR_mktag(0), Univ, UNIV_OFFSET_FOR_TYPEINFO);
").
:- pragma c_code("
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO(std_util, type_info, 0,
MR_TYPECTOR_REP_C_POINTER);
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO(std_util, univ, 0,
MR_TYPECTOR_REP_UNIV);
#ifndef COMPACT_ARGS
Declare_label(mercury____Compare___std_util__univ_0_0_i1);
MR_MAKE_PROC_LAYOUT(mercury____Compare___std_util__univ_0_0,
MR_DETISM_DET, 1, MR_LONG_LVAL_STACKVAR(1),
MR_PREDICATE, ""std_util"", ""compare_univ"", 3, 0);
MR_MAKE_INTERNAL_LAYOUT(mercury____Compare___std_util__univ_0_0, 1);
#endif
Define_extern_entry(mercury____Unify___std_util__type_info_0_0);
Define_extern_entry(mercury____Index___std_util__type_info_0_0);
Define_extern_entry(mercury____Compare___std_util__type_info_0_0);
BEGIN_MODULE(unify_univ_module)
init_entry(mercury____Unify___std_util__univ_0_0);
init_entry(mercury____Index___std_util__univ_0_0);
init_entry(mercury____Compare___std_util__univ_0_0);
init_entry(mercury____Unify___std_util__type_info_0_0);
init_entry(mercury____Index___std_util__type_info_0_0);
init_entry(mercury____Compare___std_util__type_info_0_0);
BEGIN_CODE
Define_entry(mercury____Unify___std_util__univ_0_0);
{
/*
** Unification for univ.
**
** The two inputs are in the registers named by unify_input[12].
** The success/failure indication should go in unify_output.
*/
Word univ1, univ2;
Word typeinfo1, typeinfo2;
int comp;
univ1 = r1;
univ2 = r2;
/* First check the type_infos compare equal */
typeinfo1 = MR_field(MR_mktag(0), univ1, UNIV_OFFSET_FOR_TYPEINFO);
typeinfo2 = MR_field(MR_mktag(0), univ2, UNIV_OFFSET_FOR_TYPEINFO);
save_transient_registers();
comp = MR_compare_type_info(typeinfo1, typeinfo2);
restore_transient_registers();
if (comp != MR_COMPARE_EQUAL) {
r1 = FALSE;
proceed();
}
/*
** Then invoke the generic unification predicate on the
** unwrapped args
*/
r1 = typeinfo1;
r2 = MR_field(MR_mktag(0), univ1, UNIV_OFFSET_FOR_DATA);
r3 = MR_field(MR_mktag(0), univ2, UNIV_OFFSET_FOR_DATA);
{
Declare_entry(mercury__unify_2_0);
tailcall(ENTRY(mercury__unify_2_0),
LABEL(mercury____Unify___std_util__univ_0_0));
}
}
Define_entry(mercury____Index___std_util__univ_0_0);
r1 = -1;
proceed();
Define_entry(mercury____Compare___std_util__univ_0_0);
{
/*
** Comparison for univ:
**
** The two inputs are in the registers named by compare_input[12].
** The result should go in compare_output.
*/
Word univ1, univ2;
Word typeinfo1, typeinfo2;
int comp;
univ1 = r1;
univ2 = r2;
/* First compare the type_infos */
typeinfo1 = MR_field(MR_mktag(0), univ1, UNIV_OFFSET_FOR_TYPEINFO);
typeinfo2 = MR_field(MR_mktag(0), univ2, UNIV_OFFSET_FOR_TYPEINFO);
save_transient_registers();
comp = MR_compare_type_info(typeinfo1, typeinfo2);
restore_transient_registers();
if (comp != MR_COMPARE_EQUAL) {
r1 = comp;
proceed();
}
/*
** If the types are the same, then invoke the generic compare/3
** predicate on the unwrapped args.
*/
r1 = typeinfo1;
r2 = MR_field(MR_mktag(0), univ1, UNIV_OFFSET_FOR_DATA);
r3 = MR_field(MR_mktag(0), univ2, UNIV_OFFSET_FOR_DATA);
{
Declare_entry(mercury__compare_3_0);
tailcall(ENTRY(mercury__compare_3_0),
LABEL(mercury____Compare___std_util__univ_0_0));
}
}
Define_entry(mercury____Unify___std_util__type_info_0_0);
{
/*
** Unification for type_info.
**
** The two inputs are in the registers named by unify_input[12].
** The success/failure indication should go in unify_output.
*/
int comp;
save_transient_registers();
comp = MR_compare_type_info(r1, r2);
restore_transient_registers();
r1 = (comp == MR_COMPARE_EQUAL);
proceed();
}
Define_entry(mercury____Index___std_util__type_info_0_0);
r1 = -1;
proceed();
Define_entry(mercury____Compare___std_util__type_info_0_0);
{
/*
** Comparison for type_info:
**
** The two inputs are in the registers named by compare_input[12].
** The result should go in compare_output.
*/
int comp;
save_transient_registers();
comp = MR_compare_type_info(r1, r2);
restore_transient_registers();
r1 = comp;
proceed();
}
END_MODULE
/* Ensure that the initialization code for the above module gets run. */
/*
INIT sys_init_unify_univ_module
*/
MR_MODULE_STATIC_OR_EXTERN ModuleFunc unify_univ_module;
void sys_init_unify_univ_module(void); /* suppress gcc -Wmissing-decl warning */
void sys_init_unify_univ_module(void) {
unify_univ_module();
MR_INIT_TYPE_CTOR_INFO(mercury_data_std_util__type_ctor_info_univ_0,
std_util__univ_0_0);
MR_INIT_TYPE_CTOR_INFO(mercury_data_std_util__type_ctor_info_type_info_0,
std_util__type_info_0_0);
}
").
%-----------------------------------------------------------------------------%
% Code for type manipulation.
% Prototypes and type definitions.
:- pragma c_header_code("
typedef struct ML_Construct_Info_Struct {
int vector_type;
int arity;
Word *functor_descriptor;
Word *argument_vector;
Word primary_tag;
Word secondary_tag;
ConstString functor_name;
} ML_Construct_Info;
int ML_get_num_functors(Word type_info);
Word ML_copy_argument_typeinfos(int arity, Word type_info,
Word *arg_vector);
bool ML_get_functors_check_range(int functor_number, Word type_info,
ML_Construct_Info *info);
void ML_copy_arguments_from_list_to_vector(int arity, Word arg_list,
Word term_vector);
bool ML_typecheck_arguments(Word type_info, int arity,
Word arg_list, Word* arg_vector);
Word ML_make_type(int arity, MR_TypeCtorInfo type_ctor_info,
Word arg_type_list);
").
% A type_ctor_info is really just a subtype of type_info,
% but we should hide this from users as it is an implementation
% detail.
:- type type_ctor_info == type_info.
:- pragma c_code(type_of(_Value::unused) = (TypeInfo::out),
will_not_call_mercury, "
{
TypeInfo = TypeInfo_for_T;
/*
** We used to collapse equivalences for efficiency here,
** but that's not always desirable, due to the reverse
** mode of make_type/2, and efficiency of type_infos
** probably isn't very important anyway.
*/
#if 0
save_transient_registers();
TypeInfo = MR_collapse_equivalences(TypeInfo_for_T);
restore_transient_registers();
#endif
}
").
:- pragma c_code(has_type(_Arg::unused, TypeInfo::in), will_not_call_mercury, "
TypeInfo_for_T = TypeInfo;
").
% Export this function in order to use it in runtime/mercury_trace_external.c
:- pragma export(type_name(in) = out, "ML_type_name").
type_name(Type) = TypeName :-
type_ctor_and_args(Type, TypeCtor, ArgTypes),
type_ctor_name_and_arity(TypeCtor, ModuleName, Name, Arity),
( Arity = 0 ->
UnqualifiedTypeName = Name
;
( ModuleName = "builtin", Name = "func" ->
IsFunc = yes
;
IsFunc = no
),
(
IsFunc = yes,
ArgTypes = [FuncRetType]
->
FuncRetTypeName = type_name(FuncRetType),
string__append_list(
["((func) = ", FuncRetTypeName, ")"],
UnqualifiedTypeName)
;
type_arg_names(ArgTypes, IsFunc, ArgTypeNames),
string__append_list([Name, "(" | ArgTypeNames],
UnqualifiedTypeName)
)
),
( ModuleName = "builtin" ->
TypeName = UnqualifiedTypeName
;
string__append_list([ModuleName, ":",
UnqualifiedTypeName], TypeName)
).
:- pred type_arg_names(list(type_info), bool, list(string)).
:- mode type_arg_names(in, in, out) is det.
type_arg_names([], _, []).
type_arg_names([Type|Types], IsFunc, ArgNames) :-
Name = type_name(Type),
( Types = [] ->
ArgNames = [Name, ")"]
; IsFunc = yes, Types = [FuncReturnType] ->
FuncReturnName = type_name(FuncReturnType),
ArgNames = [Name, ") = ", FuncReturnName]
;
type_arg_names(Types, IsFunc, Names),
ArgNames = [Name, ", " | Names]
).
type_args(Type) = ArgTypes :-
type_ctor_and_args(Type, _TypeCtor, ArgTypes).
type_ctor_name(TypeCtor) = Name :-
type_ctor_name_and_arity(TypeCtor, _ModuleName, Name, _Arity).
type_ctor_module_name(TypeCtor) = ModuleName :-
type_ctor_name_and_arity(TypeCtor, ModuleName, _Name, _Arity).
type_ctor_arity(TypeCtor) = Arity :-
type_ctor_name_and_arity(TypeCtor, _ModuleName, _Name, Arity).
det_make_type(TypeCtor, ArgTypes) = Type :-
( make_type(TypeCtor, ArgTypes) = NewType ->
Type = NewType
;
error("det_make_type/2: make_type/2 failed (wrong arity)")
).
:- pragma c_code(type_ctor(TypeInfo::in) = (TypeCtor::out),
will_not_call_mercury, "
{
MR_TypeCtorInfo type_ctor_info;
Word *type_info;
save_transient_registers();
type_info = (Word *) MR_collapse_equivalences(TypeInfo);
restore_transient_registers();
type_ctor_info = MR_TYPEINFO_GET_TYPE_CTOR_INFO(type_info);
TypeCtor = ML_make_ctor_info(type_info, type_ctor_info);
}
").
:- pragma c_header_code("
Word ML_make_ctor_info(Word *type_info, MR_TypeCtorInfo type_ctor_info);
/*
** Several predicates use these (the MR_TYPE_CTOR_INFO_IS_HO_*
** macros need access to these addresses).
*/
MR_DECLARE_TYPE_CTOR_INFO_STRUCT(mercury_data___type_ctor_info_pred_0);
MR_DECLARE_TYPE_CTOR_INFO_STRUCT(mercury_data___type_ctor_info_func_0);
").
:- pragma c_code("
Word ML_make_ctor_info(Word *type_info, MR_TypeCtorInfo type_ctor_info)
{
Word ctor_info = (Word) type_ctor_info;
if (MR_TYPE_CTOR_INFO_IS_HO_PRED(type_ctor_info)) {
ctor_info = MR_TYPECTOR_MAKE_PRED(
MR_TYPEINFO_GET_HIGHER_ARITY(type_info));
if (!MR_TYPECTOR_IS_HIGHER_ORDER(ctor_info)) {
fatal_error(""std_util:ML_make_ctor_info""
""- arity out of range."");
}
} else if (MR_TYPE_CTOR_INFO_IS_HO_FUNC(type_ctor_info)) {
ctor_info = MR_TYPECTOR_MAKE_FUNC(
MR_TYPEINFO_GET_HIGHER_ARITY(type_info));
if (!MR_TYPECTOR_IS_HIGHER_ORDER(ctor_info)) {
fatal_error(""std_util:ML_make_ctor_info""
""- arity out of range."");
}
}
return ctor_info;
}
").
:- pragma c_code(type_ctor_and_args(TypeInfo::in,
TypeCtor::out, TypeArgs::out), will_not_call_mercury, "
{
MR_TypeCtorInfo type_ctor_info;
Word *type_info;
Integer arity;
save_transient_registers();
type_info = (Word *) MR_collapse_equivalences(TypeInfo);
type_ctor_info = MR_TYPEINFO_GET_TYPE_CTOR_INFO(type_info);
TypeCtor = ML_make_ctor_info(type_info, type_ctor_info);
if (MR_TYPECTOR_IS_HIGHER_ORDER(TypeCtor)) {
arity = MR_TYPECTOR_GET_HOT_ARITY(TypeCtor);
TypeArgs = ML_copy_argument_typeinfos(arity, 0,
type_info + TYPEINFO_OFFSET_FOR_PRED_ARGS);
} else {
arity = MR_TYPE_CTOR_INFO_GET_TYPE_ARITY(type_ctor_info);
TypeArgs = ML_copy_argument_typeinfos(arity, 0,
type_info + OFFSET_FOR_ARG_TYPE_INFOS);
}
restore_transient_registers();
}
").
/*
** This is the forwards mode of make_type/2:
** given a type constructor and a list of argument
** types, check that the length of the argument
** types matches the arity of the type constructor,
** and if so, use the type constructor to construct
** a new type with the specified arguments.
*/
:- pragma c_code(make_type(TypeCtor::in, ArgTypes::in) = (Type::out),
will_not_call_mercury, "
{
int list_length, arity;
Word arg_type;
MR_TypeCtorInfo type_ctor_info;
type_ctor_info = (MR_TypeCtorInfo) TypeCtor;
if (MR_TYPECTOR_IS_HIGHER_ORDER(type_ctor_info)) {
arity = MR_TYPECTOR_GET_HOT_ARITY(type_ctor_info);
} else {
arity = MR_TYPE_CTOR_INFO_GET_TYPE_ARITY(type_ctor_info);
}
arg_type = ArgTypes;
for (list_length = 0; !MR_list_is_empty(arg_type); list_length++) {
arg_type = MR_list_tail(arg_type);
}
if (list_length != arity) {
SUCCESS_INDICATOR = FALSE;
} else {
save_transient_registers();
Type = ML_make_type(arity, type_ctor_info, ArgTypes);
restore_transient_registers();
SUCCESS_INDICATOR = TRUE;
}
}
").
/*
** This is the reverse mode of make_type: given a type,
** split it up into a type constructor and a list of
** arguments.
*/
:- pragma c_code(make_type(TypeCtor::out, ArgTypes::out) = (TypeInfo::in),
will_not_call_mercury, "
{
Word *type_info = (Word *) TypeInfo;
MR_TypeCtorInfo type_ctor_info =
MR_TYPEINFO_GET_TYPE_CTOR_INFO(type_info);
Integer arity;
TypeCtor = ML_make_ctor_info(type_info, type_ctor_info);
if (MR_TYPECTOR_IS_HIGHER_ORDER(TypeCtor)) {
arity = MR_TYPECTOR_GET_HOT_ARITY(type_ctor_info);
save_transient_registers();
ArgTypes = ML_copy_argument_typeinfos(arity, 0,
type_info + TYPEINFO_OFFSET_FOR_PRED_ARGS);
restore_transient_registers();
} else {
arity = MR_TYPE_CTOR_INFO_GET_TYPE_ARITY(type_ctor_info);
save_transient_registers();
ArgTypes = ML_copy_argument_typeinfos(arity, 0,
type_info + OFFSET_FOR_ARG_TYPE_INFOS);
restore_transient_registers();
}
}
").
:- pragma c_code(type_ctor_name_and_arity(TypeCtor::in,
TypeCtorModuleName::out, TypeCtorName::out,
TypeCtorArity::out), will_not_call_mercury, "
{
MR_TypeCtorInfo type_ctor = (MR_TypeCtorInfo) TypeCtor;
/* XXX zs: I think this code is wrong */
if (MR_TYPECTOR_IS_HIGHER_ORDER(type_ctor)) {
TypeCtorModuleName = (String) (Word)
MR_TYPECTOR_GET_HOT_MODULE_NAME(type_ctor);
TypeCtorName = (String) (Word)
MR_TYPECTOR_GET_HOT_NAME(type_ctor);
TypeCtorArity = MR_TYPECTOR_GET_HOT_ARITY(type_ctor);
} else {
TypeCtorModuleName = type_ctor->type_ctor_module_name;
TypeCtorName = type_ctor->type_ctor_name;
TypeCtorArity = MR_TYPE_CTOR_INFO_GET_TYPE_ARITY(type_ctor);
}
}
").
:- pragma c_code(num_functors(TypeInfo::in) = (Functors::out),
will_not_call_mercury, "
{
save_transient_registers();
Functors = ML_get_num_functors(TypeInfo);
restore_transient_registers();
}
").
:- pragma c_code(get_functor(TypeInfo::in, FunctorNumber::in,
FunctorName::out, Arity::out, TypeInfoList::out),
will_not_call_mercury, "
{
ML_Construct_Info info;
bool success;
/*
** Get information for this functor number and
** store in info. If this is a discriminated union
** type and if the functor number is in range, we
** succeed.
*/
save_transient_registers();
success = ML_get_functors_check_range(FunctorNumber,
TypeInfo, &info);
restore_transient_registers();
/*
** Get the functor name and arity, construct the list
** of type_infos for arguments.
*/
if (success) {
MR_make_aligned_string(FunctorName, (String) (Word)
info.functor_name);
Arity = info.arity;
save_transient_registers();
TypeInfoList = ML_copy_argument_typeinfos((int) Arity,
TypeInfo, info.argument_vector);
restore_transient_registers();
}
SUCCESS_INDICATOR = success;
}
").
:- pragma c_code(construct(TypeInfo::in, FunctorNumber::in, ArgList::in) =
(Term::out), will_not_call_mercury, "
{
MR_TypeCtorInfo type_ctor_info;
Word layout_entry, new_data, term_vector;
ML_Construct_Info info;
bool success;
/*
** Check range of FunctorNum, get info for this
** functor.
*/
save_transient_registers();
success =
ML_get_functors_check_range(FunctorNumber, TypeInfo, &info) &&
ML_typecheck_arguments(TypeInfo, info.arity, ArgList,
info.argument_vector);
restore_transient_registers();
/*
** Build the new term.
**
** It will be stored in `new_data', and `term_vector' is a
** the argument vector.
**
*/
if (success) {
type_ctor_info = MR_TYPEINFO_GET_TYPE_CTOR_INFO(
(Word *) TypeInfo);
layout_entry = type_ctor_info->type_ctor_layout[
info.primary_tag];
if (info.vector_type == MR_TYPE_CTOR_FUNCTORS_ENUM) {
/*
** Enumeratiors don't have tags or arguments,
** just the enumeration value.
*/
new_data = (Word) info.secondary_tag;
} else {
/*
** It must be some sort of tagged functor.
*/
if (info.vector_type == MR_TYPE_CTOR_FUNCTORS_NO_TAG) {
/*
** We set term_vector to point to
** new_data so that the argument filling
** loop will fill the argument in.
*/
term_vector = (Word) &new_data;
} else if (MR_tag(layout_entry) ==
TYPE_CTOR_LAYOUT_SHARED_REMOTE_TAG) {
/*
** Create arity + 1 words, fill in the
** secondary tag, and the term_vector will
** be the rest of the words.
*/
incr_hp_msg(new_data, info.arity + 1,
MR_PROC_LABEL, ""<unknown type from ""
""std_util:construct/3>"");
MR_field(MR_mktag(0), new_data, 0)
= info.secondary_tag;
term_vector = (Word) (new_data + sizeof(Word));
} else if (MR_tag(layout_entry) == TYPE_CTOR_LAYOUT_CONST_TAG) {
/*
** If it's a du, and this tag is
** constant, it must be a shared local
** tag.
*/
new_data = MR_mkbody(info.secondary_tag);
term_vector = (Word) NULL;
} else {
/*
** An unshared tagged word, just need to
** create arguments.
*/
incr_hp_msg(new_data, info.arity,
MR_PROC_LABEL, ""<unknown type from ""
""std_util:construct/3>"");
term_vector = (Word) new_data;
}
/*
** Copy arguments.
*/
ML_copy_arguments_from_list_to_vector(info.arity,
ArgList, term_vector);
/*
** Add tag to new_data.
*/
new_data = (Word) MR_mkword(MR_mktag(info.primary_tag),
new_data);
}
/*
** Create a univ.
*/
incr_hp_msg(Term, 2, MR_PROC_LABEL, ""std_util:univ/0"");
MR_field(MR_mktag(0), Term, UNIV_OFFSET_FOR_TYPEINFO) =
(Word) TypeInfo;
MR_field(MR_mktag(0), Term, UNIV_OFFSET_FOR_DATA) =
(Word) new_data;
}
SUCCESS_INDICATOR = success;
}
").
:- pragma c_code("
/*
** Prototypes
*/
static int ML_get_functor_info(Word type_info, int functor_number,
ML_Construct_Info *info);
/*
** ML_get_functor_info:
**
** Extract the information for functor number `functor_number',
** for the type represented by type_info.
** We succeed if the type is some sort of discriminated union.
**
** You need to save and restore transient registers around
** calls to this function.
*/
static int
ML_get_functor_info(Word type_info, int functor_number,
ML_Construct_Info *info)
{
MR_TypeCtorInfo type_ctor_info;
Word *type_ctor_functors;
type_ctor_info = MR_TYPEINFO_GET_TYPE_CTOR_INFO((Word *) type_info);
if (! MR_type_ctor_rep_is_basically_du(type_ctor_info->type_ctor_rep))
{
return FALSE;
}
type_ctor_functors = type_ctor_info->type_ctor_functors;
info->vector_type = MR_TYPE_CTOR_FUNCTORS_INDICATOR(type_ctor_functors);
switch (info->vector_type) {
case MR_TYPE_CTOR_FUNCTORS_ENUM:
info->functor_descriptor = MR_TYPE_CTOR_FUNCTORS_ENUM_VECTOR(
type_ctor_functors);
info->arity = 0;
info->argument_vector = NULL;
info->primary_tag = 0;
info->secondary_tag = functor_number;
info->functor_name =
MR_TYPE_CTOR_LAYOUT_ENUM_VECTOR_FUNCTOR_NAME(
info->functor_descriptor, functor_number);
break;
case MR_TYPE_CTOR_FUNCTORS_DU:
info->functor_descriptor =
MR_TYPE_CTOR_FUNCTORS_DU_FUNCTOR_N(
type_ctor_functors, functor_number);
info->arity = MR_TYPE_CTOR_LAYOUT_FUNCTOR_DESCRIPTOR_ARITY(
info->functor_descriptor);
info->argument_vector =
MR_TYPE_CTOR_LAYOUT_FUNCTOR_DESCRIPTOR_ARGS(
info->functor_descriptor);
info->primary_tag = MR_tag(
MR_TYPE_CTOR_LAYOUT_FUNCTOR_DESCRIPTOR_TAG(
info->functor_descriptor));
info->secondary_tag = MR_unmkbody(
MR_body(MR_TYPE_CTOR_LAYOUT_FUNCTOR_DESCRIPTOR_TAG(
info->functor_descriptor), info->primary_tag));
info->functor_name =
MR_TYPE_CTOR_LAYOUT_FUNCTOR_DESCRIPTOR_FUNCTOR_NAME(
info->functor_descriptor);
break;
case MR_TYPE_CTOR_FUNCTORS_NO_TAG:
info->functor_descriptor =
MR_TYPE_CTOR_FUNCTORS_NO_TAG_FUNCTOR(
type_ctor_functors);
info->arity = 1;
info->argument_vector = MR_TYPE_CTOR_LAYOUT_NO_TAG_VECTOR_ARGS(
info->functor_descriptor);
info->primary_tag = 0;
info->secondary_tag = 0;
info->functor_name = MR_TYPE_CTOR_LAYOUT_NO_TAG_VECTOR_FUNCTOR_NAME(
info->functor_descriptor);
break;
case MR_TYPE_CTOR_FUNCTORS_EQUIV: {
Word *equiv_type;
equiv_type = (Word *) MR_TYPE_CTOR_FUNCTORS_EQUIV_TYPE(
type_ctor_functors);
return ML_get_functor_info((Word)
MR_create_type_info((Word *) type_info,
equiv_type),
functor_number, info);
}
case MR_TYPE_CTOR_FUNCTORS_SPECIAL:
return FALSE;
case MR_TYPE_CTOR_FUNCTORS_UNIV:
return FALSE;
default:
fatal_error(""std_util:construct - unexpected type."");
}
return TRUE;
}
/*
** ML_typecheck_arguments:
**
** Given a list of univs (`arg_list'), and a vector of
** type_infos (`arg_vector'), checks that they are all of the
** same type; if so, returns TRUE, otherwise returns FALSE;
** `arg_vector' may contain type variables, these
** will be filled in by the type arguments of `type_info'.
**
** Assumes the length of the list has already been checked.
**
** You need to save and restore transient registers around
** calls to this function.
*/
bool
ML_typecheck_arguments(Word type_info, int arity, Word arg_list,
Word* arg_vector)
{
int i, comp;
Word arg_type_info, list_arg_type_info;
/* Type check list of arguments */
for (i = 0; i < arity; i++) {
if (MR_list_is_empty(arg_list)) {
return FALSE;
}
list_arg_type_info = MR_field(MR_mktag(0),
MR_list_head(arg_list), UNIV_OFFSET_FOR_TYPEINFO);
arg_type_info = (Word) MR_create_type_info(
(Word *) type_info, (Word *) arg_vector[i]);
comp = MR_compare_type_info(list_arg_type_info, arg_type_info);
if (comp != MR_COMPARE_EQUAL) {
return FALSE;
}
arg_list = MR_list_tail(arg_list);
}
/* List should now be empty */
return MR_list_is_empty(arg_list);
}
/*
** ML_copy_arguments_from_list_to_vector:
**
** Copy the arguments from a list of univs (`arg_list'),
** into the vector (`term_vector').
**
** Assumes the length of the list has already been checked.
*/
void
ML_copy_arguments_from_list_to_vector(int arity, Word arg_list,
Word term_vector)
{
int i;
for (i = 0; i < arity; i++) {
MR_field(MR_mktag(0), term_vector, i) =
MR_field(MR_mktag(0), MR_list_head(arg_list),
UNIV_OFFSET_FOR_DATA);
arg_list = MR_list_tail(arg_list);
}
}
/*
** ML_make_type(arity, type_ctor_info, arg_types_list):
**
** Construct and return a type_info for a type using the
** specified type_ctor for the type constructor,
** and using the arguments specified in arg_types_list
** for the type arguments (if any).
**
** Assumes that the arity of the type constructor represented
** by type_ctor_info and the length of the arg_types_list
** are both equal to `arity'.
**
** You need to save and restore transient registers around
** calls to this function.
*/
Word
ML_make_type(int arity, MR_TypeCtorInfo type_ctor, Word arg_types_list)
{
int i, extra_args;
Word type_ctor_info;
/*
** We need to treat higher-order predicates as a special case here.
*/
if (MR_TYPECTOR_IS_HIGHER_ORDER(type_ctor)) {
type_ctor_info = MR_TYPECTOR_GET_HOT_TYPE_CTOR_INFO(type_ctor);
extra_args = 2;
} else {
type_ctor_info = (Word) type_ctor;
extra_args = 1;
}
if (arity == 0) {
return type_ctor_info;
} else {
Word *type_info;
restore_transient_registers();
/* XXX should use incr_hp_msg() here */
incr_hp(LVALUE_CAST(Word, type_info), arity + extra_args);
save_transient_registers();
MR_field(MR_mktag(0), type_info, 0) = type_ctor_info;
if (MR_TYPECTOR_IS_HIGHER_ORDER(type_ctor)) {
MR_field(MR_mktag(0), type_info, 1) = (Word) arity;
}
for (i = 0; i < arity; i++) {
MR_field(MR_mktag(0), type_info, i + extra_args) =
MR_list_head(arg_types_list);
arg_types_list = MR_list_tail(arg_types_list);
}
return (Word) type_info;
}
}
/*
** ML_get_functors_check_range:
**
** Check that functor_number is in range, and get the functor
** info if it is. Return FALSE if it is out of range, or
** if ML_get_functor_info returns FALSE, otherwise return TRUE.
**
** You need to save and restore transient registers around
** calls to this function.
*/
bool
ML_get_functors_check_range(int functor_number, Word type_info,
ML_Construct_Info *info)
{
/*
** Check range of functor_number, get functors
** vector
*/
return functor_number < ML_get_num_functors(type_info) &&
functor_number >= 0 &&
ML_get_functor_info(type_info, functor_number, info);
}
/*
** ML_copy_argument_typeinfos:
**
** Copy `arity' type_infos from `arg_vector' onto the heap
** in a list.
**
** You need to save and restore transient registers around
** calls to this function.
*/
Word
ML_copy_argument_typeinfos(int arity, Word type_info, Word *arg_vector)
{
Word type_info_list, *functors;
restore_transient_registers();
type_info_list = MR_list_empty();
while (--arity >= 0) {
Word argument;
/* Get the argument type_info */
argument = arg_vector[arity];
/* Fill in any polymorphic type_infos */
save_transient_registers();
argument = (Word) MR_create_type_info(
(Word *) type_info, (Word *) argument);
restore_transient_registers();
/* Look past any equivalences */
save_transient_registers();
argument = MR_collapse_equivalences(argument);
restore_transient_registers();
/* Join the argument to the front of the list */
type_info_list = MR_list_cons(argument, type_info_list);
}
save_transient_registers();
return type_info_list;
}
/*
** ML_get_num_functors:
**
** Get the number of functors for a type. If it isn't a
** discriminated union, return -1.
**
** You need to save and restore transient registers around
** calls to this function.
*/
int
ML_get_num_functors(Word type_info)
{
MR_TypeCtorInfo type_ctor_info;
Word *type_ctor_functors;
int functors;
type_ctor_info = MR_TYPEINFO_GET_TYPE_CTOR_INFO((Word *) type_info);
if (! MR_type_ctor_rep_is_basically_du(type_ctor_info->type_ctor_rep))
{
return -1;
}
type_ctor_functors = type_ctor_info->type_ctor_functors;
switch ((int) MR_TYPE_CTOR_FUNCTORS_INDICATOR(type_ctor_functors)) {
case MR_TYPE_CTOR_FUNCTORS_DU:
functors = MR_TYPE_CTOR_FUNCTORS_DU_NUM_FUNCTORS(
type_ctor_functors);
break;
case MR_TYPE_CTOR_FUNCTORS_ENUM:
functors = MR_TYPE_CTOR_FUNCTORS_ENUM_NUM_FUNCTORS(
type_ctor_functors);
break;
case MR_TYPE_CTOR_FUNCTORS_EQUIV: {
Word *equiv_type;
equiv_type = (Word *)
MR_TYPE_CTOR_FUNCTORS_EQUIV_TYPE(
type_ctor_functors);
functors = ML_get_num_functors((Word)
MR_create_type_info((Word *)
type_info, equiv_type));
break;
}
case MR_TYPE_CTOR_FUNCTORS_SPECIAL:
functors = -1;
break;
case MR_TYPE_CTOR_FUNCTORS_NO_TAG:
functors = 1;
break;
case MR_TYPE_CTOR_FUNCTORS_UNIV:
functors = -1;
break;
default:
fatal_error(""std_util:ML_get_num_functors :""
"" unknown indicator"");
}
return functors;
}
").
%-----------------------------------------------------------------------------%
:- pragma c_header_code("
#include <stdio.h>
/*
* Code for functor, arg and deconstruct
*
* This relies on some C primitives that take a type_info
* and a data_word, and get a functor, arity, argument vector,
* and argument type_info vector.
*/
/* Type definitions */
/*
* The last two fields, need_functor, and need_args, must
* be set by the caller, to indicate whether ML_expand
* should copy the functor (if need_functor is non-zero) or
* the argument vector and type_info_vector (if need_args is
* non-zero). The arity will always be set.
*
* ML_expand will fill in the other fields (functor, arity,
* argument_vector, type_info_vector, and non_canonical_type)
* accordingly, but
* the values of fields not asked for should be assumed to
* contain random data when ML_expand returns.
* (that is, they should not be relied on to remain unchanged).
*/
typedef struct ML_Expand_Info_Struct {
ConstString functor;
int arity;
int num_extra_args;
Word *argument_vector;
Word *type_info_vector;
bool non_canonical_type;
bool need_functor;
bool need_args;
} ML_Expand_Info;
/* Prototypes */
void ML_expand(Word* type_info, Word *data_word_ptr, ML_Expand_Info *info);
/* NB. ML_arg() is also used by store__arg_ref in store.m */
bool ML_arg(Word term_type_info, Word *term, Word argument_index,
Word *arg_type_info, Word **argument_ptr);
").
:- pragma c_code("
Declare_entry(mercury__builtin_compare_pred_3_0);
Declare_entry(mercury__builtin_compare_non_canonical_type_3_0);
/*
** Expand the given data using its type_info, find its
** functor, arity, argument vector and type_info vector.
**
** The info.type_info_vector is allocated using MR_GC_malloc().
** (We need to use MR_GC_malloc() rather than MR_malloc() or malloc(),
** since this vector may contain pointers into the Mercury heap, and
** memory allocated with MR_malloc() or malloc() will not be traced by the
** Boehm collector.)
** It is the responsibility of the caller to deallocate this
** memory (using MR_GC_free()), and to copy any fields of this vector to
** the Mercury heap. The type_infos that the elements of
** this vector point to are either
** - already allocated on the heap.
** - constants (eg type_ctor_infos)
**
** Please note:
** ML_expand increments the heap pointer, however, on
** some platforms the register windows mean that transient
** Mercury registers may be lost. Before calling ML_expand,
** call save_transient_registers(), and afterwards, call
** restore_transient_registers().
**
** If writing a C function that calls deep_copy, make sure you
** document that around your function, save_transient_registers()
** restore_transient_registers() need to be used.
**
** If you change this code you will also have reflect any changes in
** runtime/mercury_deep_copy.c and runtime/mercury_table_any.c
**
** We use 4 space tabs here because of the level of indenting.
*/
void
ML_expand(Word* type_info, Word *data_word_ptr, ML_Expand_Info *info)
{
MR_TypeCtorInfo type_ctor_info;
MR_TypeCtorLayout type_ctor_layout;
MR_TypeCtorFunctors type_ctor_functors;
Code *compare_pred;
Word layout_for_tag;
Word layout_vector_for_tag;
Word data_value;
Word data_word;
int data_tag;
MR_DiscUnionTagRepresentation tag_rep;
type_ctor_info = MR_TYPEINFO_GET_TYPE_CTOR_INFO(type_info);
type_ctor_layout = type_ctor_info->type_ctor_layout;
type_ctor_functors = type_ctor_info->type_ctor_functors;
compare_pred = type_ctor_info->compare_pred;
info->non_canonical_type = ( compare_pred ==
ENTRY(mercury__builtin_compare_non_canonical_type_3_0) );
data_word = *data_word_ptr;
data_tag = MR_tag(data_word);
data_value = MR_body(data_word, data_tag);
switch(type_ctor_info->type_ctor_rep) {
case MR_TYPECTOR_REP_ENUM:
case MR_TYPECTOR_REP_ENUM_USEREQ:
layout_for_tag = type_ctor_layout[data_tag];
layout_vector_for_tag = MR_strip_tag(layout_for_tag);
info->functor = MR_TYPE_CTOR_LAYOUT_ENUM_VECTOR_FUNCTOR_NAME(
layout_vector_for_tag, data_word);
info->arity = 0;
info->num_extra_args = 0;
info->argument_vector = NULL;
info->type_info_vector = NULL;
break;
case MR_TYPECTOR_REP_DU:
case MR_TYPECTOR_REP_DU_USEREQ:
layout_for_tag = type_ctor_layout[data_tag];
layout_vector_for_tag = MR_strip_tag(layout_for_tag);
tag_rep = MR_get_tag_representation((Word) layout_for_tag);
switch (tag_rep) {
case MR_DISCUNIONTAG_SHARED_LOCAL:
data_value = MR_unmkbody(data_value);
info->functor = MR_TYPE_CTOR_LAYOUT_ENUM_VECTOR_FUNCTOR_NAME(
layout_vector_for_tag, data_value);
info->arity = 0;
info->num_extra_args = 0;
info->argument_vector = NULL;
info->type_info_vector = NULL;
break;
case MR_DISCUNIONTAG_SHARED_REMOTE: {
Word secondary_tag;
secondary_tag = ((Word *) data_value)[0];
/*
** Look past the secondary tag, and get the functor
** descriptor, then we can just use the code for
** unshared tags.
*/
data_value = (Word) ((Word *) data_value + 1);
layout_for_tag = (Word)
MR_TYPE_CTOR_LAYOUT_SHARED_REMOTE_VECTOR_GET_FUNCTOR_DESCRIPTOR(
layout_vector_for_tag, secondary_tag);
layout_vector_for_tag = MR_strip_tag(layout_for_tag);
} /* fallthru */
case MR_DISCUNIONTAG_UNSHARED: /* fallthru */
{
int i;
Word * functor_descriptor = (Word *) layout_vector_for_tag;
info->arity =
MR_TYPE_CTOR_LAYOUT_FUNCTOR_DESCRIPTOR_ARITY(functor_descriptor);
info->num_extra_args =
MR_TYPE_CTOR_LAYOUT_FUNCTOR_DESCRIPTOR_EXIST_VARCOUNT(functor_descriptor);
if (info->need_functor) {
MR_make_aligned_string(info->functor,
MR_TYPE_CTOR_LAYOUT_FUNCTOR_DESCRIPTOR_FUNCTOR_NAME(
functor_descriptor));
}
if (info->need_args) {
info->argument_vector = (Word *) data_value;
info->type_info_vector = MR_GC_NEW_ARRAY(Word,
info->arity);
for (i = 0; i < info->arity ; i++) {
Word *arg_pseudo_type_info;
arg_pseudo_type_info = (Word *)
MR_TYPE_CTOR_LAYOUT_FUNCTOR_DESCRIPTOR_ARGS(
functor_descriptor)[i];
info->type_info_vector[i] =
(Word) MR_create_type_info_maybe_existq(
type_info, arg_pseudo_type_info,
(Word *) data_value,
functor_descriptor);
}
}
break;
}
}
break;
case MR_TYPECTOR_REP_NOTAG:
case MR_TYPECTOR_REP_NOTAG_USEREQ:
{
int i;
Word * functor_descriptor;
layout_for_tag = type_ctor_layout[data_tag];
layout_vector_for_tag = MR_strip_tag(layout_for_tag);
functor_descriptor = (Word *) layout_vector_for_tag;
data_value = (Word) data_word_ptr;
info->arity = MR_TYPE_CTOR_LAYOUT_FUNCTOR_DESCRIPTOR_ARITY(
functor_descriptor);
info->num_extra_args = 0;
if (info->need_functor) {
MR_make_aligned_string(info->functor,
MR_TYPE_CTOR_LAYOUT_FUNCTOR_DESCRIPTOR_FUNCTOR_NAME(
functor_descriptor));
}
if (info->need_args) {
/*
* A NO_TAG is much like UNSHARED, but we use the
* data_word_ptr here to simulate an argument
* vector.
*/
info->argument_vector = (Word *) data_word_ptr;
info->type_info_vector = MR_GC_NEW_ARRAY(Word,
info->arity);
for (i = 0; i < info->arity ; i++) {
Word *arg_pseudo_type_info;
arg_pseudo_type_info = (Word *)
MR_TYPE_CTOR_LAYOUT_FUNCTOR_DESCRIPTOR_ARGS(
functor_descriptor)[i];
info->type_info_vector[i] =
(Word) MR_create_type_info_maybe_existq(
type_info, arg_pseudo_type_info,
(Word *) data_value,
functor_descriptor);
}
}
break;
}
case MR_TYPECTOR_REP_EQUIV: {
Word *equiv_type_info;
layout_for_tag = type_ctor_layout[data_tag];
layout_vector_for_tag = MR_strip_tag(layout_for_tag);
equiv_type_info = MR_create_type_info(type_info, (Word *)
MR_TYPE_CTOR_LAYOUT_EQUIV_TYPE(layout_vector_for_tag));
ML_expand(equiv_type_info, data_word_ptr, info);
break;
}
case MR_TYPECTOR_REP_EQUIV_VAR: {
Word *equiv_type_info;
layout_for_tag = type_ctor_layout[data_tag];
layout_vector_for_tag = MR_strip_tag(layout_for_tag);
equiv_type_info = MR_create_type_info(type_info,
(Word *) layout_vector_for_tag);
ML_expand(equiv_type_info, data_word_ptr, info);
break;
}
case MR_TYPECTOR_REP_INT:
if (info->need_functor) {
char buf[500];
char *str;
sprintf(buf, ""%ld"", (long) data_word);
incr_saved_hp_atomic(LVALUE_CAST(Word, str),
(strlen(buf) + sizeof(Word)) / sizeof(Word));
strcpy(str, buf);
info->functor = str;
}
info->argument_vector = NULL;
info->type_info_vector = NULL;
info->arity = 0;
info->num_extra_args = 0;
break;
case MR_TYPECTOR_REP_CHAR:
/* XXX should escape characters correctly */
if (info->need_functor) {
char *str;
incr_saved_hp_atomic(LVALUE_CAST(Word, str),
(3 + sizeof(Word)) / sizeof(Word));
sprintf(str, ""\'%c\'"", (char) data_word);
info->functor = str;
}
info->argument_vector = NULL;
info->type_info_vector = NULL;
info->arity = 0;
info->num_extra_args = 0;
break;
case MR_TYPECTOR_REP_FLOAT:
if (info->need_functor) {
char buf[500];
Float f;
char *str;
f = word_to_float(data_word);
sprintf(buf, ""%#.15g"", f);
incr_saved_hp_atomic(LVALUE_CAST(Word, str),
(strlen(buf) + sizeof(Word)) / sizeof(Word));
strcpy(str, buf);
info->functor = str;
}
info->argument_vector = NULL;
info->type_info_vector = NULL;
info->arity = 0;
info->num_extra_args = 0;
break;
case MR_TYPECTOR_REP_STRING:
/* XXX should escape characters correctly */
if (info->need_functor) {
char *str;
incr_saved_hp_atomic(LVALUE_CAST(Word, str),
(strlen((String) data_word) + 2 + sizeof(Word))
/ sizeof(Word));
sprintf(str, ""%c%s%c"", '""', (String) data_word, '""');
info->functor = str;
}
info->argument_vector = NULL;
info->type_info_vector = NULL;
info->arity = 0;
info->num_extra_args = 0;
break;
case MR_TYPECTOR_REP_PRED:
if (info->need_functor) {
MR_make_aligned_string(info->functor, ""<<predicate>>"");
}
info->argument_vector = NULL;
info->type_info_vector = NULL;
info->arity = 0;
info->num_extra_args = 0;
break;
case MR_TYPECTOR_REP_UNIV:
/*
* Univ is a two word structure, containing
* type_info and data.
*/
ML_expand((Word *)
((Word *) data_word)[UNIV_OFFSET_FOR_TYPEINFO],
&((Word *) data_word)[UNIV_OFFSET_FOR_DATA], info);
break;
case MR_TYPECTOR_REP_VOID:
/*
** There's no way to create values of type `void',
** so this should never happen.
*/
fatal_error(""ML_expand: cannot expand void types"");
case MR_TYPECTOR_REP_C_POINTER:
if (info->need_functor) {
MR_make_aligned_string(info->functor, ""<<c_pointer>>"");
}
info->argument_vector = NULL;
info->type_info_vector = NULL;
info->arity = 0;
info->num_extra_args = 0;
break;
case MR_TYPECTOR_REP_TYPEINFO:
if (info->need_functor) {
MR_make_aligned_string(info->functor, ""<<typeinfo>>"");
}
/* XXX should we return the arguments here? */
info->argument_vector = NULL;
info->type_info_vector = NULL;
info->arity = 0;
info->num_extra_args = 0;
break;
case MR_TYPECTOR_REP_TYPECLASSINFO:
if (info->need_functor) {
MR_make_aligned_string(info->functor, ""<<typeclassinfo>>"");
}
/* XXX should we return the arguments here? */
info->argument_vector = NULL;
info->type_info_vector = NULL;
info->arity = 0;
info->num_extra_args = 0;
break;
case MR_TYPECTOR_REP_ARRAY:
if (info->need_functor) {
MR_make_aligned_string(info->functor, ""<<array>>"");
}
/* XXX should we return the arguments here? */
info->argument_vector = NULL;
info->type_info_vector = NULL;
info->arity = 0;
info->num_extra_args = 0;
break;
case MR_TYPECTOR_REP_SUCCIP:
if (info->need_functor) {
MR_make_aligned_string(info->functor, ""<<succip>>"");
}
info->argument_vector = NULL;
info->type_info_vector = NULL;
info->arity = 0;
info->num_extra_args = 0;
break;
case MR_TYPECTOR_REP_HP:
if (info->need_functor) {
MR_make_aligned_string(info->functor, ""<<hp>>"");
}
info->argument_vector = NULL;
info->type_info_vector = NULL;
info->arity = 0;
info->num_extra_args = 0;
break;
case MR_TYPECTOR_REP_CURFR:
if (info->need_functor) {
MR_make_aligned_string(info->functor, ""<<curfr>>"");
}
info->argument_vector = NULL;
info->type_info_vector = NULL;
info->arity = 0;
info->num_extra_args = 0;
break;
case MR_TYPECTOR_REP_MAXFR:
if (info->need_functor) {
MR_make_aligned_string(info->functor, ""<<maxfr>>"");
}
info->argument_vector = NULL;
info->type_info_vector = NULL;
info->arity = 0;
info->num_extra_args = 0;
break;
case MR_TYPECTOR_REP_REDOFR:
if (info->need_functor) {
MR_make_aligned_string(info->functor, ""<<redofr>>"");
}
info->argument_vector = NULL;
info->type_info_vector = NULL;
info->arity = 0;
info->num_extra_args = 0;
break;
case MR_TYPECTOR_REP_REDOIP:
if (info->need_functor) {
MR_make_aligned_string(info->functor, ""<<redoip>>"");
}
info->argument_vector = NULL;
info->type_info_vector = NULL;
info->arity = 0;
info->num_extra_args = 0;
break;
case MR_TYPECTOR_REP_TRAIL_PTR:
if (info->need_functor) {
MR_make_aligned_string(info->functor, ""<<trail_ptr>>"");
}
info->argument_vector = NULL;
info->type_info_vector = NULL;
info->arity = 0;
info->num_extra_args = 0;
break;
case MR_TYPECTOR_REP_TICKET:
if (info->need_functor) {
MR_make_aligned_string(info->functor, ""<<ticket>>"");
}
info->argument_vector = NULL;
info->type_info_vector = NULL;
info->arity = 0;
info->num_extra_args = 0;
break;
case MR_TYPECTOR_REP_UNKNOWN: /* fallthru */
default:
fatal_error(""ML_expand: cannot expand -- unknown data type"");
break;
}
}
/*
** ML_arg() is a subroutine used to implement arg/2, argument/2,
** and also store__arg_ref/5 in store.m.
** It takes a term (& its type), and an argument index,
** and returns a
*/
bool
ML_arg(Word term_type_info, Word *term_ptr, Word argument_index,
Word *arg_type_info, Word **argument_ptr)
{
ML_Expand_Info info;
Word arg_pseudo_type_info;
bool success;
info.need_functor = FALSE;
info.need_args = TRUE;
ML_expand((Word *) term_type_info, term_ptr, &info);
/*
** Check for attempts to deconstruct a non-canonical type:
** such deconstructions must be cc_multi, and since
** arg/2 is det, we must treat violations of this
** as runtime errors.
** (There ought to be a cc_multi version of arg/2
** that allows this.)
*/
if (info.non_canonical_type) {
fatal_error(""called argument/2 for a type with a ""
""user-defined equality predicate"");
}
/* Check range */
success = (argument_index >= 0 && argument_index < info.arity);
if (success) {
/* figure out the type of the argument */
arg_pseudo_type_info = info.type_info_vector[argument_index];
if (TYPEINFO_IS_VARIABLE(arg_pseudo_type_info)) {
*arg_type_info =
((Word *) term_type_info)[arg_pseudo_type_info];
} else {
*arg_type_info = arg_pseudo_type_info;
}
*argument_ptr = &info.argument_vector[argument_index];
}
/*
** Free the allocated type_info_vector, since we just copied
** the stuff we want out of it.
*/
MR_GC_free(info.type_info_vector);
return success;
}
").
%-----------------------------------------------------------------------------%
% Code for functor, arg and deconstruct.
:- pragma c_code(functor(Term::in, Functor::out, Arity::out),
will_not_call_mercury, "
{
ML_Expand_Info info;
info.need_functor = TRUE;
info.need_args = FALSE;
save_transient_registers();
ML_expand((Word *) TypeInfo_for_T, &Term, &info);
restore_transient_registers();
/*
** Check for attempts to deconstruct a non-canonical type:
** such deconstructions must be cc_multi, and since
** functor/2 is det, we must treat violations of this
** as runtime errors.
** (There ought to be a cc_multi version of functor/2
** that allows this.)
*/
if (info.non_canonical_type) {
fatal_error(""called functor/2 for a type with a ""
""user-defined equality predicate"");
}
/* Copy functor onto the heap */
MR_make_aligned_string(LVALUE_CAST(ConstString, Functor),
info.functor);
Arity = info.arity;
}").
/*
** N.B. any modifications to arg/2 might also require similar
** changes to store__arg_ref in store.m.
*/
:- pragma c_code(arg(Term::in, ArgumentIndex::in) = (Argument::out),
will_not_call_mercury, "
{
Word arg_type_info;
Word *argument_ptr;
bool success;
int comparison_result;
save_transient_registers();
success = ML_arg(TypeInfo_for_T, &Term, ArgumentIndex, &arg_type_info,
&argument_ptr);
if (success) {
/* compare the actual type with the expected type */
comparison_result =
MR_compare_type_info(arg_type_info, TypeInfo_for_ArgT);
success = (comparison_result == MR_COMPARE_EQUAL);
if (success) {
Argument = *argument_ptr;
}
}
restore_transient_registers();
SUCCESS_INDICATOR = success;
}").
:- pragma c_code(argument(Term::in, ArgumentIndex::in) = (ArgumentUniv::out),
will_not_call_mercury, "
{
Word arg_type_info;
Word *argument_ptr;
bool success;
save_transient_registers();
success = ML_arg(TypeInfo_for_T, &Term, ArgumentIndex, &arg_type_info,
&argument_ptr);
restore_transient_registers();
if (success) {
/* Allocate enough room for a univ */
incr_hp_msg(ArgumentUniv, 2, MR_PROC_LABEL,
""std_util:univ/0"");
MR_field(MR_mktag(0), ArgumentUniv, UNIV_OFFSET_FOR_TYPEINFO) =
arg_type_info;
MR_field(MR_mktag(0), ArgumentUniv, UNIV_OFFSET_FOR_DATA)
= *argument_ptr;
}
SUCCESS_INDICATOR = success;
}").
det_arg(Type, ArgumentIndex) = Argument :-
(
arg(Type, ArgumentIndex) = Argument0
->
Argument = Argument0
;
( argument(Type, ArgumentIndex) = _ArgumentUniv ->
error("det_arg: argument number out of range")
;
error("det_arg: argument had wrong type")
)
).
det_argument(Type, ArgumentIndex) = Argument :-
(
argument(Type, ArgumentIndex) = Argument0
->
Argument = Argument0
;
error("det_argument: argument out of range")
).
:- pragma c_code(deconstruct(Term::in, Functor::out, Arity::out,
Arguments::out), will_not_call_mercury, "
{
ML_Expand_Info info;
Word arg_pseudo_type_info;
Word Argument, tmp;
int i;
info.need_functor = TRUE;
info.need_args = TRUE;
save_transient_registers();
ML_expand((Word *) TypeInfo_for_T, &Term, &info);
restore_transient_registers();
/*
** Check for attempts to deconstruct a non-canonical type:
** such deconstructions must be cc_multi, and since
** deconstruct/4 is det, we must treat violations of this
** as runtime errors.
** (There ought to be a cc_multi version of deconstruct/4
** that allows this.)
*/
if (info.non_canonical_type) {
fatal_error(""called deconstruct/4 for a type with a ""
""user-defined equality predicate"");
}
/* Get functor */
MR_make_aligned_string(LVALUE_CAST(ConstString, Functor),
info.functor);
/* Get arity */
Arity = info.arity;
/* Build argument list */
Arguments = MR_list_empty_msg(MR_PROC_LABEL);
i = info.arity;
while (--i >= 0) {
/* Create an argument on the heap */
incr_hp_msg(Argument, 2, MR_PROC_LABEL, ""std_util:univ/0"");
/* Join the argument to the front of the list */
Arguments = MR_list_cons_msg(Argument, Arguments,
MR_PROC_LABEL);
/* Fill in the arguments */
arg_pseudo_type_info = info.type_info_vector[i];
if (TYPEINFO_IS_VARIABLE(arg_pseudo_type_info)) {
/* It's a type variable, get its value */
MR_field(MR_mktag(0), Argument,
UNIV_OFFSET_FOR_TYPEINFO) =
((Word *) TypeInfo_for_T)[arg_pseudo_type_info];
}
else {
/* It's already a type_info */
MR_field(MR_mktag(0), Argument,
UNIV_OFFSET_FOR_TYPEINFO) =
arg_pseudo_type_info;
}
/* Fill in the data */
MR_field(MR_mktag(0), Argument, UNIV_OFFSET_FOR_DATA) =
info.argument_vector[i + info.num_extra_args];
}
/* Free the allocated type_info_vector, since we just copied
* all its arguments onto the heap.
*/
MR_GC_free(info.type_info_vector);
}").
%-----------------------------------------------------------------------------%
% This predicate returns the type_info for the type std_util:type_info.
% It is intended for use from C code, since Mercury code can access
% this type_info easily enough even without this predicate.
:- pred get_type_info_for_type_info(type_info).
:- mode get_type_info_for_type_info(out) is det.
:- pragma export(get_type_info_for_type_info(out),
"ML_get_type_info_for_type_info").
get_type_info_for_type_info(TypeInfo) :-
Type = type_of(1),
TypeInfo = type_of(Type).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
% Ralph Becket <rwab1@cam.sri.com> 24/04/99
% Function forms added.
:- interface.
:- func pair(T1, T2) = pair(T1, T2).
:- func maybe_func(func(T1) = T2, T1) = maybe(T2).
:- mode maybe_func(func(in) = out is semidet, in) = out is det.
% General purpose higher-order programming constructs.
% compose(F, G, X) = F(G(X))
%
% Function composition.
% XXX It would be nice to have infix `o' or somesuch for this.
:- func compose(func(T2) = T3, func(T1) = T2, T1) = T3.
% converse(F, X, Y) = F(Y, X)
:- func converse(func(T1, T2) = T3, T2, T1) = T3.
% pow(F, N, X) = F^N(X)
%
% Function exponentiation.
:- func pow(func(T) = T, int, T) = T.
% ---------------------------------------------------------------------------- %
% ---------------------------------------------------------------------------- %
:- implementation.
pair(X, Y) =
X-Y.
maybe_func(PF, X) =
( if Y = PF(X) then yes(Y) else no ).
compose(F, G, X) =
F(G(X)).
converse(F, X, Y) =
F(Y, X).
pow(F, N, X) =
( if N = 0 then X else pow(F, N - 1, F(X)) ).