Files
mercury/library/term.m
Fergus Henderson 247b1c24b9 Fix various invasions of the user's namespace by `mercury_builtin.m',
Estimated hours taken: 6

Fix various invasions of the user's namespace by `mercury_builtin.m',
by splitting mercury_builtin.m into two modules, called builtin.m and
private_builtin.m, and ensuring that the latter is imported as if
by `:- use_module' rather than `:- import_module'.

library/builtin.m:
library/private_builtin.m:
	Split mercury_builtin.m into two modules, builtin.m,
	which contains stuff intended to be public,
	and private_builtin.m, which contains implementation
	details that are not supposed to be public.

library/mercury_builtin.m:
	Add a comment saying that this module is no longer used, and
	should eventually be removed.  I have not removed it yet, since
	that would prevent bootstrapping with the current compiler.  It
	will be removed as a seperate change later, once all the
	changes have propagated.

compiler/prog_util.m:
	Change the definition of mercury_private_builtin_module/1 and
	mercury_public_builtin_module so that instead of automatically
	importing mercury_builtin.m as if by `import_module', the
	copiler will now automatically import builtin.m as if by
	`import_module' and private_builtin.m as if by `use_module'.

compiler/polymorphism.m:
	Change a call to mercury_private_builtin_module/1 for
	unsafe_promise_unique to instead call mercury_public_builtin_module/1.

compiler/unify_proc.m:
	Avoid hard-coding "mercury_builtin" by instead
	calling one of  mercury_{private,public}_builtin_module/1.

runtime/mercury_type_info.[ch]:
library/term.m:
library/std_util.m:
compiler/code_util.m:
	Change a few hard-coded instances of "mercury_builtin"
	to "builtin" or "private_builtin" as appropriate.

runtime/mercury_trace_util.c:
runtime/mercury_trace_internal.c:
library/prolog.m:
compiler/*.m:
	Update comments that refer to "mercury_builtin" to instead
	refer to either "builtin" or "private_builtin".

doc/Mmakefile:
	Don't include the interface to private_builtin.m in the
	library reference manual.

tools/bootcheck:
	Add `-p'/`--copy-profiler' option.  This is needed to get
	the above changes to bootstrap.

tools/test_mercury:
	Pass `-p' to tools/bootcheck.

tests/term/*.trans_opt_exp:
	s/mercury_builtin/builtin/g
1998-05-25 21:55:28 +00:00

1123 lines
38 KiB
Mathematica

%---------------------------------------------------------------------------%
% Copyright (C) 1993-1998 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: term.m.
% Main author: fjh.
% Stability: medium.
% This file provides a type `term' used to represent Prolog terms,
% and various predicates to manipulate terms and substitutions.
%-----------------------------------------------------------------------------%
:- module term.
:- interface.
:- import_module list, map, std_util.
%-----------------------------------------------------------------------------%
:- type term ---> term__functor(const, list(term), term__context)
; term__variable(var).
:- type const ---> term__atom(string)
; term__integer(int)
; term__string(string)
; term__float(float).
:- type term__context ---> term__context(string, int).
% file name, line number.
:- type var.
:- type var_supply.
%-----------------------------------------------------------------------------%
% The following predicates can convert values of (almost)
% any type to the type `term' and back again.
:- type term_to_type_result(T)
---> ok(T)
; error(term_to_type_error).
:- pred term__try_term_to_type(term, term_to_type_result(T)).
:- mode term__try_term_to_type(in, out) is det.
% term__try_term_to_type(Term, Result):
% Try to convert the given term to a ground value of type T.
% If successful, return `ok(X)' where X is the converted value.
% If Term is not ground, return `mode_error(Var, Context)',
% where Var is a variable occurring in Term.
% If Term is not a valid term of the specified type, return
% `type_error(SubTerm, ExpectedType, Context, ArgContexts)',
% where SubTerm is a sub-term of Term and ExpectedType is
% the type expected for that part of Term.
% Context specifies the file and line number where the
% offending part of the term was read in from, if available.
% ArgContexts specifies the path from the root of the term
% to the offending subterm.
:- type term_to_type_error
---> type_error(term, type_info, term__context,
term_to_type_context)
; mode_error(var, term_to_type_context).
:- type term_to_type_context == list(term_to_type_arg_context).
:- type term_to_type_arg_context
---> arg_context(
const, % functor
int, % argument number (starting from 1)
term__context % filename & line number
).
:- pred term__term_to_type(term, T).
:- mode term__term_to_type(in, out) is semidet.
% term_to_type(Term, Type) :- try_term_to_type(Term, ok(Type)).
:- pred term__det_term_to_type(term, T).
:- mode term__det_term_to_type(in, out) is det.
% like term_to_type, but calls error/1 rather than failing.
:- pred term__type_to_term(T, term).
:- mode term__type_to_term(in, out) is det.
% converts a value to a term representation of that value
:- pred term__univ_to_term(univ, term).
:- mode term__univ_to_term(in, out) is det.
% calls term__type_to_term on the value stored in the univ
% (as distinct from the univ itself).
%-----------------------------------------------------------------------------%
:- pred term__vars(term, list(var)).
:- mode term__vars(in, out) is det.
% term__vars(Term, Vars)
% Vars is the list of variables contained in Term, in the order
% obtained by traversing the term depth first, left-to-right.
:- pred term__vars_2(term, list(var), list(var)).
:- mode term__vars_2(in, in, out) is det.
% As above, but with an accumulator.
:- pred term__vars_list(list(term), list(var)).
:- mode term__vars_list(in, out) is det.
% term__vars_list(TermList, Vars)
% Vars is the list of variables contained in TermList, in the
% order obtained by traversing the list of terms depth-first,
% left-to-right.
:- pred term__contains_var(term, var).
:- mode term__contains_var(in, in) is semidet.
:- mode term__contains_var(in, out) is nondet.
% term__contains_var(Term, Var)
% True if Term contains Var. (On backtracking returns all the
% variables contained in Term.)
:- pred term__contains_var_list(list(term), var).
:- mode term__contains_var_list(in, in) is semidet.
:- mode term__contains_var_list(in, out) is nondet.
% term__contains_var_list(TermList, Var)
% True if TermList contains Var. (On backtracking returns all the
% variables contained in Term.)
:- type substitution == map(var, term).
:- pred term__unify(term, term, substitution, substitution).
:- mode term__unify(in, in, in, out) is semidet.
% term__unify(Term1, Term2, Bindings0, Bindings)
% unify (with occur check) two terms with respect to a set
% of bindings and possibly update the set of bindings
:- pred term__substitute(term, var, term, term).
:- mode term__substitute(in, in, in, out) is det.
% term__substitute(Term0, Var, Replacement, Term) :
% replace all occurrences of Var in Term0 with Replacement,
% and return the result in Term.
:- pred term__substitute_list(list(term), var, term, list(term)).
:- mode term__substitute_list(in, in, in, out) is det.
% as above, except for a list of terms rather than a single term
:- pred term__substitute_corresponding(list(var), list(term), term, term).
:- mode term__substitute_corresponding(in, in, in, out) is det.
% term__substitute_corresponding(Vars, Repls, Term0, Term).
% replace all occurrences of variables in Vars with
% the corresponding term in Repls, and return the result in Term.
% If Vars contains duplicates, or if Vars is not the same
% length as Repls, the behaviour is undefined and probably
% harmful.
:- pred term__substitute_corresponding_list(list(var), list(term), list(term),
list(term)).
:- mode term__substitute_corresponding_list(in, in, in, out) is det.
% term__substitute_corresponding_list(Vars, Repls, TermList0, TermList).
% As above, except applies to a list of terms rather than a
% single term.
:- pred term__apply_rec_substitution(term, substitution, term).
:- mode term__apply_rec_substitution(in, in, out) is det.
% term__apply_rec_substitution(Term0, Substitution, Term) :
% recursively apply substitution to Term0 until
% no more substitions can be applied, and then
% return the result in Term.
:- pred term__apply_rec_substitution_to_list(list(term), substitution,
list(term)).
:- mode term__apply_rec_substitution_to_list(in, in, out) is det.
:- pred term__apply_substitution(term, substitution, term).
:- mode term__apply_substitution(in, in, out) is det.
% term__apply_substitution(Term0, Substitution, Term) :
% apply substitution to Term0 and return the result in Term.
:- pred term__apply_substitution_to_list(list(term), substitution,
list(term)).
:- mode term__apply_substitution_to_list(in, in, out) is det.
% term__apply_substitution_to_list(TermList0, Substitution, TermList) :
% as above, except for a list of terms rather than a single term
:- pred term__occurs(term, var, substitution).
:- mode term__occurs(in, in, in) is semidet.
% term__occurs(Term0, Var, Substitution) :
% true iff Var occurs in the term resulting after
% applying Substitution to Term0.
:- pred term__occurs_list(list(term), var, substitution).
:- mode term__occurs_list(in, in, in) is semidet.
% as above, except for a list of terms rather than a single term
:- pred term__relabel_variable(term, var, var, term).
:- mode term__relabel_variable(in, in, in, out) is det.
% term__relabel_variable(Term0, OldVar, NewVar, Term) :
% replace all occurences of OldVar in Term0 with
% NewVar and put the result in Term.
:- pred term__relabel_variables(list(term), var, var, list(term)).
:- mode term__relabel_variables(in, in, in, out) is det.
% term__relabel_variables(Terms0, OldVar, NewVar, Terms) :
% same as term__relabel_variable but for a list of terms.
:- pred term__apply_variable_renaming(term, map(var, var), term).
:- mode term__apply_variable_renaming(in, in, out) is det.
% same as term__relabel_variable, except relabels
% multiple variables. If a variable is not in the
% map, it is not replaced.
:- pred term__apply_variable_renaming_to_list(list(term), map(var, var),
list(term)).
:- mode term__apply_variable_renaming_to_list(in, in, out) is det.
% applies term__apply_variable_renaming to a list of terms.
:- pred term__is_ground(term, substitution).
:- mode term__is_ground(in, in) is semidet.
% term__is_ground(Term, Bindings) is true iff no variables contained
% in Term are non-ground in Bindings.
:- pred term__is_ground(term).
:- mode term__is_ground(in) is semidet.
% term__is_ground(Term) is true iff Term contains no variables.
:- pred term__compare(comparison_result, term, term, substitution).
:- mode term__compare(out, in, in, in) is semidet.
% term__compare(Comparison, Term1, Term2, Bindings) is true iff
% there is a binding of Comparison to <, =, or > such
% that the binding holds for the two ground terms Term1
% and Term2 with respect to the bindings in Bindings.
% Fails if Term1 or Term2 is not ground (with respect to
% the bindings in Bindings).
%-----------------------------------------------------------------------------%
% To manage a supply of variables, use the following 2 predicates.
% (We might want to give these a unique mode later.)
:- pred term__init_var_supply(var_supply).
:- mode term__init_var_supply(out) is det.
:- mode term__init_var_supply(in) is semidet. % implied
% term__init_var_supply(VarSupply) :
% returns a fresh var_supply for producing fresh variables.
:- pred term__create_var(var_supply, var, var_supply).
:- mode term__create_var(in, out, out) is det.
% term__create_var(VarSupply0, Variable, VarSupply) :
% create a fresh variable (var) and return the
% updated var_supply.
:- pred term__var_to_int(var, int).
:- mode term__var_to_int(in, out) is det.
% Convert a variable to an int.
% Different variables map to different ints.
% Other than that, the mapping is unspecified.
%-----------------------------------------------------------------------------%
% Given a term context, return the source line number.
:- pred term__context_line(term__context, int).
:- mode term__context_line(in, out) is det.
% Given a term context, return the source file.
:- pred term__context_file(term__context, string).
:- mode term__context_file(in, out) is det.
% Used to initialize the term context when reading in
% (or otherwise constructing) a term.
:- pred term__context_init(term__context).
:- mode term__context_init(out) is det.
:- pred term__context_init(string, int, term__context).
:- mode term__context_init(in, in, out) is det.
% Convert a list of terms which are all vars into a list
% of vars. Abort (call error/1) if the list contains
% any non-variables.
:- pred term__term_list_to_var_list(list(term), list(var)).
:- mode term__term_list_to_var_list(in, out) is det.
% Convert a list of terms which are all vars into a list
% of vars (or vice versa).
:- pred term__var_list_to_term_list(list(var), list(term)).
:- mode term__var_list_to_term_list(in, out) is det.
:- mode term__var_list_to_term_list(out, in) is semidet.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module std_util, require, array, int, string.
%-----------------------------------------------------------------------------%
:- type var_supply == int.
:- type var == int.
%-----------------------------------------------------------------------------%
term__term_to_type(Term, Val) :-
term__try_term_to_type(Term, ok(Val)).
term__try_term_to_type(Term, Result) :-
term__try_term_to_univ(Term, type_of(ValTypedVar), UnivResult),
(
UnivResult = ok(Univ),
det_univ_to_type(Univ, Val),
same_type(Val, ValTypedVar),
Result = ok(Val)
;
UnivResult = error(Error),
Result = error(Error)
).
:- pred term__try_term_to_univ(term::in, type_info::in,
term_to_type_result(univ)::out) is det.
term__try_term_to_univ(Term, Type, Result) :-
term__try_term_to_univ_2(Term, Type, [], Result).
:- pred term__try_term_to_univ_2(term::in, type_info::in,
term_to_type_context::in,
term_to_type_result(univ)::out) is det.
term__try_term_to_univ_2(term__variable(Var), _Type, Context,
error(mode_error(Var, Context))).
term__try_term_to_univ_2(Term, Type, Context, Result) :-
Term = term__functor(Functor, ArgTerms, TermContext),
(
type_ctor_and_args(Type, TypeCtor, TypeArgs),
term__term_to_univ_special_case(
type_ctor_module_name(TypeCtor),
type_ctor_name(TypeCtor),
TypeArgs, Term, Type, Context, SpecialCaseResult)
->
Result = SpecialCaseResult
;
Functor = term__atom(FunctorName),
list__length(ArgTerms, Arity),
find_functor(Type, FunctorName, Arity, FunctorNumber, ArgTypes),
term__term_list_to_univ_list(ArgTerms, ArgTypes,
Functor, 1, Context, TermContext, ArgsResult)
->
(
ArgsResult = ok(ArgValues),
( Value = construct(Type, FunctorNumber, ArgValues) ->
Result = ok(Value)
;
error("term_to_type: construct/3 failed")
)
;
ArgsResult = error(Error),
Result = error(Error)
)
;
% the arg contexts are built up in reverse order,
% so we need to reverse them here
list__reverse(Context, RevContext),
Result = error(type_error(Term, Type, TermContext, RevContext))
).
:- pred term__term_to_univ_special_case(string::in, string::in,
list(type_info)::in,
term::in(bound(term__functor(ground, ground, ground))),
type_info::in, term_to_type_context::in,
term_to_type_result(univ)::out) is semidet.
/*
** XXX the following clauses for mercury_builtin:* are
** for bootstrapping only, and should eventually be deleted
*/
term__term_to_univ_special_case("mercury_builtin", "character", [],
Term, _, _, ok(Univ)) :-
Term = term__functor(term__atom(FunctorName), [], _),
string__first_char(FunctorName, Char, ""),
type_to_univ(Char, Univ).
term__term_to_univ_special_case("mercury_builtin", "int", [],
Term, _, _, ok(Univ)) :-
Term = term__functor(term__integer(Int), [], _),
type_to_univ(Int, Univ).
term__term_to_univ_special_case("mercury_builtin", "string", [],
Term, _, _, ok(Univ)) :-
Term = term__functor(term__string(String), [], _),
type_to_univ(String, Univ).
term__term_to_univ_special_case("mercury_builtin", "float", [],
Term, _, _, ok(Univ)) :-
Term = term__functor(term__float(Float), [], _),
type_to_univ(Float, Univ).
term__term_to_univ_special_case("builtin", "character", [],
Term, _, _, ok(Univ)) :-
Term = term__functor(term__atom(FunctorName), [], _),
string__first_char(FunctorName, Char, ""),
type_to_univ(Char, Univ).
term__term_to_univ_special_case("builtin", "int", [],
Term, _, _, ok(Univ)) :-
Term = term__functor(term__integer(Int), [], _),
type_to_univ(Int, Univ).
term__term_to_univ_special_case("builtin", "string", [],
Term, _, _, ok(Univ)) :-
Term = term__functor(term__string(String), [], _),
type_to_univ(String, Univ).
term__term_to_univ_special_case("builtin", "float", [],
Term, _, _, ok(Univ)) :-
Term = term__functor(term__float(Float), [], _),
type_to_univ(Float, Univ).
term__term_to_univ_special_case("array", "array", [ElemType], Term, _Type,
PrevContext, Result) :-
%
% arrays are represented as terms of the form
% array([elem1, elem2, ...])
%
Term = term__functor(term__atom("array"), [ArgList], TermContext),
% To convert such terms back to arrays, we first
% convert the term representing the list of elements back to a list,
% and then (if successful) we just call the array/1 function.
%
ListTypeCtor = type_ctor(type_of([0])),
ListType = det_make_type(ListTypeCtor, [ElemType]),
ArgContext = arg_context(term__atom("array"), 1, TermContext),
NewContext = [ArgContext | PrevContext],
term__try_term_to_univ_2(ArgList, ListType, NewContext, ArgResult),
(
ArgResult = ok(ListUniv),
/***************
% XXX existential types not yet implemented...
% :- some [T] pred has_type(T::unused, type_info::in) is det.
has_type(List, ListType),
det_univ_to_type(ListUniv, List),
Array = array(List),
Result = ok(univ(Array))
****************/
% since we don't have existential types, we have to use
% some unsafe casts...
require_equal(univ_type(ListUniv), ListType),
list_of_any(List), % explicit type qualification
% to avoid unbound type variables
List = unsafe_cast(univ_value_as_type_any(ListUniv)),
Array = array(List),
ArrayTypeCtor = type_ctor(type_of(Array)),
ArrayType = det_make_type(ArrayTypeCtor, [ElemType]),
Result = ok(unsafe_any_to_univ(ArrayType, unsafe_cast(Array)))
;
ArgResult = error(Error),
Result = error(Error)
).
term__term_to_univ_special_case("builtin", "c_pointer", _, _, _,
_, _) :-
fail.
term__term_to_univ_special_case("std_util", "univ", _, _, _, _, _) :-
% Implementing this properly would require keeping a
% global table mapping from type names to type_infos
% for all of the types in the program...
% so for the moment, we don't allow it.
fail.
term__term_to_univ_special_case("std_util", "type_info", _, _, _, _, _) :-
% ditto
fail.
:- pred same_type(T::unused, T::unused) is det.
same_type(_, _).
:- pred term__term_list_to_univ_list(list(term)::in, list(type_info)::in,
term__const::in, int::in, term_to_type_context::in,
term__context::in, term_to_type_result(list(univ))::out)
is semidet.
term__term_list_to_univ_list([], [], _, _, _, _, ok([])).
term__term_list_to_univ_list([ArgTerm|ArgTerms], [Type|Types],
Functor, ArgNum, PrevContext, TermContext, Result) :-
ArgContext = arg_context(Functor, ArgNum, TermContext),
NewContext = [ArgContext | PrevContext],
term__try_term_to_univ_2(ArgTerm, Type, NewContext, ArgResult),
(
ArgResult = ok(Arg),
term__term_list_to_univ_list(ArgTerms, Types, Functor,
ArgNum + 1, PrevContext, TermContext, RestResult),
(
RestResult = ok(Rest),
Result = ok([Arg | Rest])
;
RestResult = error(Error),
Result = error(Error)
)
;
ArgResult = error(Error),
Result = error(Error)
).
:- pred term__find_functor(type_info::in, string::in, int::in, int::out,
list(type_info)::out) is semidet.
term__find_functor(Type, Functor, Arity, FunctorNumber, ArgTypes) :-
N = num_functors(Type),
term__find_functor_2(Type, Functor, Arity, N, FunctorNumber, ArgTypes).
:- pred term__find_functor_2(type_info::in, string::in, int::in, int::in,
int::out, list(type_info)::out) is semidet.
term__find_functor_2(TypeInfo, Functor, Arity, Num, FunctorNumber, ArgTypes) :-
Num >= 0,
Num1 = Num - 1,
(
get_functor(TypeInfo, Num1, Functor, Arity, ArgTypes1)
->
ArgTypes = ArgTypes1,
FunctorNumber = Num1
;
term__find_functor_2(TypeInfo, Functor, Arity, Num1,
FunctorNumber, ArgTypes)
).
term__det_term_to_type(Term, X) :-
( term__term_to_type(Term, X1) ->
X = X1
; \+ term__is_ground(Term) ->
error("term__det_term_to_type failed, because the term wasn't ground")
;
string__append_list([
"term__det_term_to_type failed, due to a type error:\n",
"the term wasn't a valid term for type `",
type_name(type_of(X)),
"'"], Message),
error(Message)
).
%-----------------------------------------------------------------------------%
/**********
XXX existential types not yet implemented
:- some [T] pred has_type(T::unused, type_info::in) is det.
:- pragma c_code(has_type(Arg::unused, TypeInfo::in), will_not_call_mercury,
"TypeInfo_for_T = TypeInfo;"
).
**********/
:- func unsafe_cast(T1::in) = (T2::out) is det.
:- pragma c_code(unsafe_cast(VarIn::in) = (VarOut::out), will_not_call_mercury,
"VarOut = VarIn;").
:- type any == c_pointer.
:- pred array_of_any(array(any)::unused) is det.
array_of_any(_).
:- pred list_of_any(list(any)::unused) is det.
list_of_any(_).
:- func univ_value_as_type_any(univ) = any.
:- pragma c_code(univ_value_as_type_any(Univ::in) = (Val::out),
will_not_call_mercury,
"
Val = field(mktag(0), Univ, UNIV_OFFSET_FOR_DATA);
").
:- func unsafe_any_to_univ(type_info, any) = univ.
% 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(unsafe_any_to_univ(TypeInfo::in, Value::in) = (Univ::out),
will_not_call_mercury,
"
incr_hp(Univ, 2);
field(mktag(0), Univ, UNIV_OFFSET_FOR_TYPEINFO) = (Word) TypeInfo;
field(mktag(0), Univ, UNIV_OFFSET_FOR_DATA) = (Word) Value;
").
%-----------------------------------------------------------------------------%
term__type_to_term(Val, Term) :- type_to_univ(Val, Univ),
term__univ_to_term(Univ, Term).
term__univ_to_term(Univ, Term) :-
term__context_init(Context),
Type = univ_type(Univ),
% NU-Prolog barfs on `num_functors(Type) < 0'
( num_functors(Type) = N, N < 0 ->
(
type_ctor_and_args(Type, TypeCtor, TypeArgs),
TypeName = type_ctor_name(TypeCtor),
ModuleName = type_ctor_module_name(TypeCtor),
term__univ_to_term_special_case(ModuleName, TypeName,
TypeArgs, Univ, Context, SpecialCaseTerm)
->
Term = SpecialCaseTerm
;
string__append_list(
["term__type_to_term: unknown type `",
type_name(univ_type(Univ)),
"'"],
Message),
error(Message)
)
;
deconstruct(Univ, FunctorString, _FunctorArity, FunctorArgs),
term__univ_list_to_term_list(FunctorArgs, TermArgs),
Term = term__functor(term__atom(FunctorString), TermArgs,
Context)
).
:- pred term__univ_to_term_special_case(string::in, string::in,
list(type_info)::in, univ::in, term__context::in,
term::out) is semidet.
/*
** XXX the following clauses for mercury_builtin:* are
** for bootstrapping only, and should eventually be deleted
*/
term__univ_to_term_special_case("mercury_builtin", "int", [], Univ, Context,
term__functor(term__integer(Int), [], Context)) :-
det_univ_to_type(Univ, Int).
term__univ_to_term_special_case("mercury_builtin", "float", [], Univ, Context,
term__functor(term__float(Float), [], Context)) :-
det_univ_to_type(Univ, Float).
term__univ_to_term_special_case("mercury_builtin", "character", [], Univ,
Context, term__functor(term__atom(CharName), [], Context)) :-
det_univ_to_type(Univ, Character),
string__char_to_string(Character, CharName).
term__univ_to_term_special_case("mercury_builtin", "string", [], Univ, Context,
term__functor(term__string(String), [], Context)) :-
det_univ_to_type(Univ, String).
term__univ_to_term_special_case("builtin", "int", [], Univ, Context,
term__functor(term__integer(Int), [], Context)) :-
det_univ_to_type(Univ, Int).
term__univ_to_term_special_case("builtin", "float", [], Univ, Context,
term__functor(term__float(Float), [], Context)) :-
det_univ_to_type(Univ, Float).
term__univ_to_term_special_case("builtin", "character", [], Univ,
Context, term__functor(term__atom(CharName), [], Context)) :-
det_univ_to_type(Univ, Character),
string__char_to_string(Character, CharName).
term__univ_to_term_special_case("builtin", "string", [], Univ, Context,
term__functor(term__string(String), [], Context)) :-
det_univ_to_type(Univ, String).
term__univ_to_term_special_case("std_util", "type_info", [], Univ, Context,
term__functor(term__atom("type_info"), [Term], Context)) :-
det_univ_to_type(Univ, TypeInfo),
type_info_to_term(Context, TypeInfo, Term).
term__univ_to_term_special_case("std_util", "univ", [], Univ, Context, Term) :-
Term = term__functor(term__atom("univ"),
% XXX what operator should we use for type
% qualification?
[term__functor(term__atom(":"), % TYPE_QUAL_OP
[ValueTerm, TypeTerm],
Context)], Context),
/****
XXX existential types not implemented
det_univ_to_type(univ_value(Univ), UnivValue),
****/
% instead, we use some unsafe casts...
require_equal(univ_type(Univ), type_of(UnivValue)),
UnivValue = unsafe_cast(univ_value_as_type_any(Univ)),
type_info_to_term(Context, univ_type(UnivValue), TypeTerm),
term__univ_to_term(UnivValue, ValueTerm).
term__univ_to_term_special_case("array", "array", [ElemType], Univ, Context,
Term) :-
Term = term__functor(term__atom("array"), [ArgsTerm], Context),
ListTypeCtor = type_ctor(type_of([0])),
ListType = det_make_type(ListTypeCtor, [ElemType]),
/***
XXX existential types not yet implemented
has_type(List, ListType),
det__univ_to_type(Univ, Array),
array__to_list(Array, List),
term__type_to_term(List, ArgsTerm).
***/
% instead, we need to use some unsafe casts...
array_of_any(Array), % explicit type qualification
% to avoid unbound type variables
Array = unsafe_cast(univ_value_as_type_any(Univ)),
array__to_list(Array, List),
ListUniv = unsafe_any_to_univ(ListType, unsafe_cast(List)),
term__univ_to_term(ListUniv, ArgsTerm).
:- pred term__univ_list_to_term_list(list(univ)::in,
list(term)::out) is det.
term__univ_list_to_term_list([], []).
term__univ_list_to_term_list([Value|Values], [Term|Terms]) :-
term__univ_to_term(Value, Term),
term__univ_list_to_term_list(Values, Terms).
% given a type_info, return a term that represents the name of that type.
:- pred type_info_to_term(term__context::in, type_info::in, term::out) is det.
type_info_to_term(Context, TypeInfo, Term) :-
type_ctor_and_args(TypeInfo, TypeCtor, ArgTypes),
TypeName = type_ctor_name(TypeCtor),
ModuleName = type_ctor_name(TypeCtor),
list__map(type_info_to_term(Context), ArgTypes, ArgTerms),
/*
** XXX the test for mercury_builtin is for bootstrapping only,
** and should eventually be deleted
*/
( (ModuleName = "mercury_builtin" ; ModuleName = "builtin") ->
Term = term__functor(term__atom(TypeName), ArgTerms, Context)
;
Term = term__functor(term__atom(":"),
[term__functor(term__atom(ModuleName), [], Context),
term__functor(term__atom(TypeName),
ArgTerms, Context)], Context)
).
:- pred require_equal(T::in, T::in) is det.
require_equal(X, Y) :-
( X = Y ->
true
;
error("require_equal failed")
).
%-----------------------------------------------------------------------------%
% term__vars(Term, Vars) is true if Vars is the list of variables
% contained in Term obtained by depth-first left-to-right traversal
% in that order.
term__vars(Term, Vars) :-
term__vars_2(Term, [], Vars).
term__vars_list(Terms, Vars) :-
term__vars_2_list(Terms, [], Vars).
term__vars_2(term__variable(V), Vs, [V|Vs]).
term__vars_2(term__functor(_,Args,_), Vs0, Vs) :-
term__vars_2_list(Args, Vs0, Vs).
:- pred term__vars_2_list(list(term), list(var), list(var)).
:- mode term__vars_2_list(in, in, out) is det.
term__vars_2_list([], Vs, Vs).
term__vars_2_list([T|Ts], Vs0, Vs) :-
term__vars_2_list(Ts, Vs0, Vs1),
term__vars_2(T, Vs1, Vs).
%-----------------------------------------------------------------------------%
% term__contains_var(Term, Var) is true if Var occurs in Term.
term__contains_var(term__variable(V), V).
term__contains_var(term__functor(_, Args, _), V) :-
term__contains_var_list(Args, V).
term__contains_var_list([T|_], V) :-
term__contains_var(T, V).
term__contains_var_list([_|Ts], V) :-
term__contains_var_list(Ts, V).
%-----------------------------------------------------------------------------%
% term__contains_functor(Term, Functor, Args):
% term__functor(Functor, Args, _) is a subterm of Term.
%
% CURRENTLY NOT USED.
:- pred term__contains_functor(term, const, list(term)).
% :- mode term__contains_functor(in, in, in) is semidet.
:- mode term__contains_functor(in, out, out) is nondet.
term__contains_functor(term__functor(Functor, Args, _), Functor, Args).
term__contains_functor(term__functor(_, Args, _), SubFunctor, SubArgs) :-
list__member(SubTerm, Args),
term__contains_functor(SubTerm, SubFunctor, SubArgs).
%-----------------------------------------------------------------------------%
% term__subterm(Term, SubTerm):
% SubTerm is a subterm of Term.
%
% CURRENTLY NOT USED.
:- pred term__subterm(term, term).
:- mode term__subterm(in, in) is semidet.
:- mode term__subterm(in, out) is multidet.
term__subterm(Term, Term).
term__subterm(term__functor(_, Args, _), SubTerm) :-
list__member(Term, Args),
term__subterm(Term, SubTerm).
%-----------------------------------------------------------------------------%
% Access predicates for the term__context data structure.
% Given a term context, return the source line number.
term__context_line(term__context(_, LineNumber), LineNumber).
% Given a term context, return the source file.
term__context_file(term__context(FileName, _), FileName).
% Used to initialize the term context when reading in
% (or otherwise constructing) a term.
term__context_init(term__context("", 0)).
term__context_init(File, LineNumber, term__context(File, LineNumber)).
%-----------------------------------------------------------------------------%
% Unify two terms (with occurs check), updating the bindings of
% the variables in the terms.
:- term__unify(X, Y, _, _) when X and Y. % NU-Prolog indexing
term__unify(term__variable(X), term__variable(Y), Bindings0, Bindings) :-
( %%% if some [BindingOfX]
map__search(Bindings0, X, BindingOfX)
->
( %%% if some [BindingOfY]
map__search(Bindings0, Y, BindingOfY)
->
% both X and Y already have bindings - just
% unify the terms they are bound to
term__unify(BindingOfX, BindingOfY, Bindings0, Bindings)
;
% Y is a variable which hasn't been bound yet
term__apply_rec_substitution(BindingOfX, Bindings0,
SubstBindingOfX),
( SubstBindingOfX = term__variable(Y) ->
Bindings = Bindings0
;
\+ term__occurs(SubstBindingOfX, Y, Bindings0),
map__set(Bindings0, Y, SubstBindingOfX,
Bindings)
)
)
;
( %%% if some [BindingOfY2]
map__search(Bindings0, Y, BindingOfY2)
->
% X is a variable which hasn't been bound yet
term__apply_rec_substitution(BindingOfY2, Bindings0,
SubstBindingOfY2),
( SubstBindingOfY2 = term__variable(X) ->
Bindings = Bindings0
;
\+ term__occurs(SubstBindingOfY2, X, Bindings0),
map__set(Bindings0, X, SubstBindingOfY2,
Bindings)
)
;
% both X and Y are unbound variables -
% bind one to the other
( X = Y ->
Bindings = Bindings0
;
map__set(Bindings0, X, term__variable(Y),
Bindings)
)
)
).
term__unify(term__variable(X), term__functor(F, As, C), Bindings0, Bindings) :-
( %%% if some [BindingOfX]
map__search(Bindings0, X, BindingOfX)
->
term__unify(BindingOfX, term__functor(F, As, C), Bindings0,
Bindings)
;
\+ term__occurs_list(As, X, Bindings0),
map__set(Bindings0, X, term__functor(F, As, C), Bindings)
).
term__unify(term__functor(F, As, C), term__variable(X), Bindings0, Bindings) :-
( %%% if some [BindingOfX]
map__search(Bindings0, X, BindingOfX)
->
term__unify(term__functor(F, As, C), BindingOfX, Bindings0,
Bindings)
;
\+ term__occurs_list(As, X, Bindings0),
map__set(Bindings0, X, term__functor(F, As, C), Bindings)
).
term__unify(term__functor(F, AsX, _), term__functor(F, AsY, _)) -->
term__unify_list(AsX, AsY).
:- pred term__unify_list(list(term), list(term), substitution, substitution).
:- mode term__unify_list(in, in, in, out) is semidet.
term__unify_list([], []) --> [].
term__unify_list([X | Xs], [Y | Ys]) -->
term__unify(X, Y),
term__unify_list(Xs, Ys).
%-----------------------------------------------------------------------------%
% term__occurs(Term, Var, Subst) succeeds if Term contains Var,
% perhaps indirectly via the substitution. (The variable must
% not be mapped by the substitution.)
term__occurs(term__variable(X), Y, Bindings) :-
(
X = Y
->
true
;
map__search(Bindings, X, BindingOfX),
term__occurs(BindingOfX, Y, Bindings)
).
term__occurs(term__functor(_F, As, _), Y, Bindings) :-
term__occurs_list(As, Y, Bindings).
term__occurs_list([Term | Terms], Y, Bindings) :-
(
term__occurs(Term, Y, Bindings)
->
true
;
term__occurs_list(Terms, Y, Bindings)
).
%-----------------------------------------------------------------------------%
% term__substitute(Term0, Var, Replacement, Term) :
% replace all occurrences of Var in Term0 with Replacement,
% and return the result in Term.
term__substitute(term__variable(Var), SearchVar, Replacement, Term) :-
(
Var = SearchVar
->
Term = Replacement
;
Term = term__variable(Var)
).
term__substitute(term__functor(Name, Args0, Context), Var, Replacement,
term__functor(Name, Args, Context)) :-
term__substitute_list(Args0, Var, Replacement, Args).
term__substitute_list([], _Var, _Replacement, []).
term__substitute_list([Term0 | Terms0], Var, Replacement, [Term | Terms]) :-
term__substitute(Term0, Var, Replacement, Term),
term__substitute_list(Terms0, Var, Replacement, Terms).
term__substitute_corresponding(Ss, Rs, Term0, Term) :-
map__init(Subst0),
( term__substitute_corresponding_2(Ss, Rs, Subst0, Subst) ->
term__apply_substitution(Term0, Subst, Term)
;
error("term__substitute_corresponding: different length lists")
).
term__substitute_corresponding_list(Ss, Rs, TermList0, TermList) :-
map__init(Subst0),
( term__substitute_corresponding_2(Ss, Rs, Subst0, Subst) ->
term__apply_substitution_to_list(TermList0, Subst, TermList)
;
error(
"term__substitute_corresponding_list: different length lists"
)
).
:- pred term__substitute_corresponding_2(list(var), list(term),
substitution, substitution).
:- mode term__substitute_corresponding_2(in, in, in, out) is semidet.
term__substitute_corresponding_2([], [], Subst, Subst).
term__substitute_corresponding_2([S | Ss], [R | Rs], Subst0, Subst) :-
map__set(Subst0, S, R, Subst1),
term__substitute_corresponding_2(Ss, Rs, Subst1, Subst).
%-----------------------------------------------------------------------------%
term__apply_rec_substitution(term__variable(Var), Substitution, Term) :-
(
%some [Replacement]
map__search(Substitution, Var, Replacement)
->
% recursively apply the substition to the replacement
term__apply_rec_substitution(Replacement, Substitution, Term)
;
Term = term__variable(Var)
).
term__apply_rec_substitution(term__functor(Name, Args0, Context), Substitution,
term__functor(Name, Args, Context)) :-
term__apply_rec_substitution_to_list(Args0, Substitution, Args).
term__apply_rec_substitution_to_list([], _Substitution, []).
term__apply_rec_substitution_to_list([Term0 | Terms0], Substitution,
[Term | Terms]) :-
term__apply_rec_substitution(Term0, Substitution, Term),
term__apply_rec_substitution_to_list(Terms0, Substitution, Terms).
%-----------------------------------------------------------------------------%
term__apply_substitution(term__variable(Var), Substitution, Term) :-
(
%some [Replacement]
map__search(Substitution, Var, Replacement)
->
Term = Replacement
;
Term = term__variable(Var)
).
term__apply_substitution(term__functor(Name, Args0, Context), Substitution,
term__functor(Name, Args, Context)) :-
term__apply_substitution_to_list(Args0, Substitution, Args).
term__apply_substitution_to_list([], _Substitution, []).
term__apply_substitution_to_list([Term0 | Terms0], Substitution,
[Term | Terms]) :-
term__apply_substitution(Term0, Substitution, Term),
term__apply_substitution_to_list(Terms0, Substitution, Terms).
%-----------------------------------------------------------------------------%
% create a new supply of variables
term__init_var_supply(0).
% We number variables using sequential numbers,
term__create_var(VarSupply0, VarSupply, VarSupply) :-
VarSupply is VarSupply0 + 1.
%-----------------------------------------------------------------------------%
term__var_to_int(Var, Var).
%-----------------------------------------------------------------------------%
% substitute a variable name in a term.
term__relabel_variable(term__functor(Const, Terms0, Cont), OldVar, NewVar,
term__functor(Const, Terms, Cont)) :-
term__relabel_variables(Terms0, OldVar, NewVar, Terms).
term__relabel_variable(term__variable(Var0), OldVar, NewVar,
term__variable(Var)) :-
(
Var0 = OldVar
->
Var = NewVar
;
Var = Var0
).
term__relabel_variables([], _, _, []).
term__relabel_variables([Term0|Terms0], OldVar, NewVar, [Term|Terms]):-
term__relabel_variable(Term0, OldVar, NewVar, Term),
term__relabel_variables(Terms0, OldVar, NewVar, Terms).
term__apply_variable_renaming(term__functor(Const, Args0, Cont), Renaming,
term__functor(Const, Args, Cont)) :-
term__apply_variable_renaming_to_list(Args0, Renaming, Args).
term__apply_variable_renaming(term__variable(Var0), Renaming,
term__variable(Var)) :-
(
map__search(Renaming, Var0, NewVar)
->
Var = NewVar
;
Var = Var0
).
term__apply_variable_renaming_to_list([], _, []).
term__apply_variable_renaming_to_list([Term0|Terms0], Renaming, [Term|Terms]) :-
term__apply_variable_renaming(Term0, Renaming, Term),
term__apply_variable_renaming_to_list(Terms0, Renaming, Terms).
%-----------------------------------------------------------------------------%
:- term__term_list_to_var_list(Terms, Vars) when Terms or Vars. % Indexing
term__term_list_to_var_list(Terms, Vars) :-
( term__var_list_to_term_list(Vars0, Terms) ->
Vars = Vars0
;
error("term__term_list_to_var_list")
).
:- term__var_list_to_term_list(Terms, Vars) when Terms or Vars. % Indexing
term__var_list_to_term_list([], []).
term__var_list_to_term_list([Var | Vars], [term__variable(Var) | Terms]) :-
term__var_list_to_term_list(Vars, Terms).
%-----------------------------------------------------------------------------%
term__is_ground(term__variable(V), Bindings) :-
map__search(Bindings, V, Binding),
term__is_ground(Binding, Bindings).
term__is_ground(term__functor(_, Args, _), Bindings) :-
term__is_ground_2(Args, Bindings).
:- pred term__is_ground_2(list(term), substitution).
:- mode term__is_ground_2(in, in) is semidet.
term__is_ground_2([], _Bindings).
term__is_ground_2([Term|Terms], Bindings) :-
term__is_ground(Term, Bindings),
term__is_ground_2(Terms, Bindings).
%-----------------------------------------------------------------------------%
term__is_ground(term__functor(_, Args, _)) :-
term__is_ground_2(Args).
:- pred term__is_ground_2(list(term)).
:- mode term__is_ground_2(in) is semidet.
term__is_ground_2([]).
term__is_ground_2([Term|Terms]) :-
term__is_ground(Term),
term__is_ground_2(Terms).
%-----------------------------------------------------------------------------%
term__compare(Cmp, Term1, Term2, Bindings) :-
term__apply_rec_substitution(Term1, Bindings, TermA),
term__is_ground(TermA, Bindings),
term__apply_rec_substitution(Term2, Bindings, TermB),
term__is_ground(TermB, Bindings),
compare(Cmp, TermA, TermB).
%-----------------------------------------------------------------------------%