mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-15 13:55:07 +00:00
Estimated hours taken: 0.25 compiler/prog_util.m: Expand eqivalence types in `:- func' declarations.
306 lines
12 KiB
Mathematica
306 lines
12 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1995 University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module prog_util.
|
|
:- interface.
|
|
:- import_module string, varset, prog_io, list.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% The following predicate prog_util__expand_eqv_types traverses
|
|
% through the list of items. Each time it finds an eqv_type
|
|
% definition, it replaces all occurrences of the type (both
|
|
% before and after it in the list of items) with type that it
|
|
% is equivalent to. This has the effect of eliminating all the
|
|
% equivalence types from the source code. Circular equivalence
|
|
% types in the input will cause references to undefined types
|
|
% in the output.
|
|
|
|
:- pred prog_util__expand_eqv_types(list(item_and_context),
|
|
list(item_and_context)).
|
|
:- mode prog_util__expand_eqv_types(in, out) is det.
|
|
|
|
% The following predicate prog_util__replace_eqv_type_list
|
|
% performs substititution of a single type on a list
|
|
% of items. It is used in mercury_to_goedel to rename
|
|
% type `int' as `integer'.
|
|
|
|
:- pred prog_util__replace_eqv_type_list(list(item_and_context), varset,
|
|
string, list(type_param), type, list(item_and_context)).
|
|
:- mode prog_util__replace_eqv_type_list(in, in, in, in, in, out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Convert a (possibly module-qualified) sym_name into a string.
|
|
|
|
:- pred unqualify_name(sym_name, string).
|
|
:- mode unqualify_name(in, out) is det.
|
|
|
|
:- pred sym_name_get_module_name(sym_name, module_name, module_name).
|
|
:- mode sym_name_get_module_name(in, in, out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% A pred declaration may contains just types, as in
|
|
% :- pred list__append(list(T), list(T), list(T)).
|
|
% or it may contain both types and modes, as in
|
|
% :- pred list__append(list(T)::in, list(T)::in,
|
|
% list(T)::output).
|
|
%
|
|
% This predicate takes the argument list of a pred declaration,
|
|
% splits it into two separate lists for the types and (if present)
|
|
% the modes.
|
|
|
|
:- type maybe_modes == maybe(list(mode)).
|
|
|
|
:- pred split_types_and_modes(list(type_and_mode), list(type), maybe_modes).
|
|
:- mode split_types_and_modes(in, out, out) is det.
|
|
|
|
:- pred split_type_and_mode(type_and_mode, type, maybe(mode)).
|
|
:- mode split_type_and_mode(in, out, out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
:- import_module bool, std_util, term.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
prog_util__expand_eqv_types(Items0, Items) :-
|
|
prog_util__replace_all_eqv_types(Items0, [], Items1),
|
|
list__reverse(Items1, Items).
|
|
|
|
:- pred prog_util__replace_all_eqv_types(list(item_and_context),
|
|
list(item_and_context), list(item_and_context)).
|
|
:- mode prog_util__replace_all_eqv_types(in, in, out) is det.
|
|
|
|
prog_util__replace_all_eqv_types([], Items, Items).
|
|
prog_util__replace_all_eqv_types([ItemContext | Items0], ItemList0,
|
|
ItemList) :-
|
|
ItemContext = Item - _Context,
|
|
( Item = type_defn(VarSet, eqv_type(Name, Args, Body), _Cond) ->
|
|
unqualify_name(Name, Name2),
|
|
prog_util__replace_eqv_type_list(ItemList0, VarSet, Name2,
|
|
Args, Body, ItemList1),
|
|
prog_util__replace_eqv_type_list(Items0, VarSet, Name2, Args,
|
|
Body, Items1)
|
|
;
|
|
Items1 = Items0,
|
|
ItemList1 = ItemList0
|
|
),
|
|
ItemList2 = [ItemContext | ItemList1],
|
|
prog_util__replace_all_eqv_types(Items1, ItemList2, ItemList).
|
|
|
|
prog_util__replace_eqv_type_list([], _, _, _, _, []).
|
|
prog_util__replace_eqv_type_list([Item0 - Context| Items0], VarSet, Name, Args,
|
|
Body, [Item - Context| Items]) :-
|
|
% Attempting to replace an equivalence type can cause
|
|
% quite a bit of memory allocation. If it turns out that
|
|
% we don't need to replace anything, then we fail so that
|
|
% we can quickly reclaim this memory.
|
|
(
|
|
%some [Item1]
|
|
prog_util__replace_eqv_type(Item0, VarSet, Name, Args, Body,
|
|
Item1)
|
|
->
|
|
Item = Item1
|
|
;
|
|
Item = Item0
|
|
),
|
|
prog_util__replace_eqv_type_list(Items0, VarSet, Name, Args, Body,
|
|
Items).
|
|
|
|
:- pred prog_util__replace_eqv_type(item, varset, string, list(type_param),
|
|
type, item).
|
|
:- mode prog_util__replace_eqv_type(in, in, in, in, in, out) is semidet.
|
|
|
|
prog_util__replace_eqv_type(type_defn(VarSet0, TypeDefn0, Cond),
|
|
TVarSet, Name, Args0, Body0,
|
|
type_defn(VarSet0, TypeDefn, Cond)) :-
|
|
varset__merge_subst(VarSet0, TVarSet, _, Subst),
|
|
term__apply_substitution_to_list(Args0, Subst, Args),
|
|
term__apply_substitution(Body0, Subst, Body),
|
|
prog_util__replace_eqv_type_defn(TypeDefn0, Name, Args, Body, TypeDefn).
|
|
|
|
prog_util__replace_eqv_type(pred(VarSet0, PredName, TypesAndModes0, Det, Cond),
|
|
TVarSet, Name, Args0, Body0,
|
|
pred(VarSet0, PredName, TypesAndModes, Det, Cond)) :-
|
|
varset__merge_subst(VarSet0, TVarSet, _, Subst),
|
|
term__apply_substitution_to_list(Args0, Subst, Args),
|
|
term__apply_substitution(Body0, Subst, Body),
|
|
prog_util__replace_eqv_type_tms(TypesAndModes0, Name, Args, Body,
|
|
no, TypesAndModes, yes).
|
|
|
|
prog_util__replace_eqv_type(
|
|
func(VarSet0, PredName, TypesAndModes0,
|
|
RetTypeAndMode0, Det, Cond),
|
|
TVarSet, Name, Args0, Body0,
|
|
func(VarSet0, PredName, TypesAndModes, RetTypeAndMode,
|
|
Det, Cond)) :-
|
|
varset__merge_subst(VarSet0, TVarSet, _, Subst),
|
|
term__apply_substitution_to_list(Args0, Subst, Args),
|
|
term__apply_substitution(Body0, Subst, Body),
|
|
prog_util__replace_eqv_type_tms(TypesAndModes0, Name, Args, Body,
|
|
no, TypesAndModes, Found),
|
|
prog_util__replace_eqv_type_tm(RetTypeAndMode0, Name, Args, Body,
|
|
Found, RetTypeAndMode, yes).
|
|
|
|
:- pred prog_util__replace_eqv_type_defn(type_defn, string, list(type_param),
|
|
type, type_defn).
|
|
:- mode prog_util__replace_eqv_type_defn(in, in, in, in, out) is semidet.
|
|
|
|
prog_util__replace_eqv_type_defn(eqv_type(TName, TArgs, TBody0),
|
|
Name, Args, Body,
|
|
eqv_type(TName, TArgs, TBody)) :-
|
|
prog_util__replace_eqv_type_type(TBody0, Name, Args, Body, no,
|
|
TBody, yes).
|
|
|
|
prog_util__replace_eqv_type_defn(uu_type(TName, TArgs, TBody0),
|
|
Name, Args, Body,
|
|
uu_type(TName, TArgs, TBody)) :-
|
|
prog_util__replace_eqv_type_uu(TBody0, Name, Args, Body, no,
|
|
TBody, yes).
|
|
|
|
prog_util__replace_eqv_type_defn(du_type(TName, TArgs, TBody0),
|
|
Name, Args, Body,
|
|
du_type(TName, TArgs, TBody)) :-
|
|
prog_util__replace_eqv_type_du(TBody0, Name, Args, Body, no,
|
|
TBody, yes).
|
|
|
|
:- pred prog_util__replace_eqv_type_uu(list(type), string, list(type_param),
|
|
type, bool, list(type), bool).
|
|
:- mode prog_util__replace_eqv_type_uu(in, in, in, in, in, out, out) is det.
|
|
|
|
prog_util__replace_eqv_type_uu([], _Name, _Args, _Body, Found, [], Found).
|
|
prog_util__replace_eqv_type_uu([T0|Ts0], Name, Args, Body, Found0, [T|Ts],
|
|
Found) :-
|
|
prog_util__replace_eqv_type_type(T0, Name, Args, Body, Found0,
|
|
T, Found1),
|
|
prog_util__replace_eqv_type_uu(Ts0, Name, Args, Body, Found1,
|
|
Ts, Found).
|
|
|
|
:- pred prog_util__replace_eqv_type_du(list(constructor), string,
|
|
list(type_param), type, bool, list(constructor), bool).
|
|
:- mode prog_util__replace_eqv_type_du(in, in, in, in, in, out, out) is det.
|
|
|
|
prog_util__replace_eqv_type_du([], _Name, _Args, _Body, Found, [], Found).
|
|
prog_util__replace_eqv_type_du([T0|Ts0], Name, Args, Body, Found0,
|
|
[T|Ts], Found) :-
|
|
prog_util__replace_eqv_type_ctor(T0, Name, Args, Body, Found0,
|
|
T, Found1),
|
|
prog_util__replace_eqv_type_du(Ts0, Name, Args, Body, Found1,
|
|
Ts, Found).
|
|
|
|
:- pred prog_util__replace_eqv_type_ctor(constructor, string, list(type_param),
|
|
type, bool, constructor, bool).
|
|
:- mode prog_util__replace_eqv_type_ctor(in, in, in, in, in, out, out) is det.
|
|
|
|
prog_util__replace_eqv_type_ctor(TName - Targs0, Name, Args, Body, Found0,
|
|
TName - Targs, Found) :-
|
|
prog_util__replace_eqv_type_uu(Targs0, Name, Args, Body, Found0,
|
|
Targs, Found).
|
|
|
|
:- pred prog_util__replace_eqv_type_type(type, string, list(type_param),
|
|
type, bool, type, bool).
|
|
:- mode prog_util__replace_eqv_type_type(in, in, in, in, in, out, out) is det.
|
|
|
|
prog_util__replace_eqv_type_type(term__variable(V), _Name, _Args, _Body, Found,
|
|
term__variable(V), Found).
|
|
prog_util__replace_eqv_type_type(term__functor(F, TArgs0, Context), Name, Args,
|
|
Body, Found0, Type, Found) :-
|
|
prog_util__replace_eqv_type_uu(TArgs0, Name, Args, Body, Found0,
|
|
TArgs1, Found1),
|
|
(
|
|
F = term__atom(Name),
|
|
list__same_length(TArgs1, Args)
|
|
->
|
|
term__term_list_to_var_list(Args, Args2),
|
|
term__substitute_corresponding(Args2, TArgs1, Body, Type),
|
|
Found = yes
|
|
;
|
|
% could we improve efficiency here by reclaiming
|
|
% garbage (or avoiding allocating it in the first place)?
|
|
Found = Found1,
|
|
Type = term__functor(F, TArgs1, Context)
|
|
).
|
|
|
|
:- pred prog_util__replace_eqv_type_tms(list(type_and_mode), string,
|
|
list(type_param), type, bool, list(type_and_mode), bool).
|
|
:- mode prog_util__replace_eqv_type_tms(in, in, in, in, in, out, out) is det.
|
|
|
|
prog_util__replace_eqv_type_tms([], _Name, _Args, _Body, Found, [], Found).
|
|
prog_util__replace_eqv_type_tms([TM0|TMs0], Name, Args, Body, Found0,
|
|
[TM|TMs], Found) :-
|
|
prog_util__replace_eqv_type_tm(TM0, Name, Args, Body, Found0,
|
|
TM, Found1),
|
|
prog_util__replace_eqv_type_tms(TMs0, Name, Args, Body, Found1,
|
|
TMs, Found).
|
|
|
|
:- pred prog_util__replace_eqv_type_tm(type_and_mode, string, list(type_param),
|
|
type, bool, type_and_mode, bool).
|
|
:- mode prog_util__replace_eqv_type_tm(in, in, in, in, in, out, out) is det.
|
|
|
|
prog_util__replace_eqv_type_tm(type_only(Type0), Name, Args, Body, Found0,
|
|
type_only(Type), Found) :-
|
|
prog_util__replace_eqv_type_type(Type0, Name, Args, Body, Found0, Type,
|
|
Found).
|
|
|
|
prog_util__replace_eqv_type_tm(type_and_mode(Type0, Mode), Name, Args,
|
|
Body, Found0,
|
|
type_and_mode(Type, Mode), Found) :-
|
|
prog_util__replace_eqv_type_type(Type0, Name, Args, Body, Found0, Type,
|
|
Found).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
unqualify_name(unqualified(PredName), PredName).
|
|
unqualify_name(qualified(_ModuleName, PredName), PredName).
|
|
|
|
sym_name_get_module_name(unqualified(_), ModuleName, ModuleName).
|
|
sym_name_get_module_name(qualified(ModuleName, _PredName), _, ModuleName).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
split_types_and_modes(TypesAndModes, Types, MaybeModes) :-
|
|
split_types_and_modes_2(TypesAndModes, yes, Types, Modes, Result),
|
|
(
|
|
Result = yes
|
|
->
|
|
MaybeModes = yes(Modes)
|
|
;
|
|
MaybeModes = no
|
|
).
|
|
|
|
:- pred split_types_and_modes_2(list(type_and_mode), bool,
|
|
list(type), list(mode), bool).
|
|
:- mode split_types_and_modes_2(in, in, out, out, out) is det.
|
|
|
|
% T = type, M = mode, TM = combined type and mode
|
|
split_types_and_modes_2([], Result, [], [], Result).
|
|
split_types_and_modes_2([TM|TMs], Result0, [T|Ts], [M|Ms], Result) :-
|
|
split_type_and_mode(TM, Result0, T, M, Result1),
|
|
split_types_and_modes_2(TMs, Result1, Ts, Ms, Result).
|
|
|
|
% if a pred declaration specifies modes for some but
|
|
% not all of the arguments, then the modes are ignored
|
|
% - should this be an error instead?
|
|
|
|
:- pred split_type_and_mode(type_and_mode, bool, type, mode, bool).
|
|
:- mode split_type_and_mode(in, in, out, out, out) is det.
|
|
|
|
split_type_and_mode(type_only(T), _, T, (free -> free), no).
|
|
split_type_and_mode(type_and_mode(T,M), R, T, M, R).
|
|
|
|
split_type_and_mode(type_only(T), T, no).
|
|
split_type_and_mode(type_and_mode(T,M), T, yes(M)).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|