[m-rev.] for post-commit review: erlang rtti improvements
Peter Wang
novalazy at gmail.com
Fri Aug 31 11:07:19 AEST 2007
Estimated hours taken: 10
Branches: main
Improvements to the Erlang backend RTTI implementation.
- Remember the lexical order of discriminated union functors, and use that
for functor numbers, as in the C backends.
- Change the representation of type_ctor_descs, which are now different from
the representation of type_ctor_infos in the case of variable arity types
(higher order types and tuples). This is necessary so we can get the arity
from a variable arity type_ctor_desc.
- Implement some related procedures:
construct.get_functor_ordinal
construct.get_functor_lex
deconstruct.functor_number
deconstruct.functor_number_cc
compiler/erl_rtti.m:
compiler/erlang_rtti.m:
For d.u. functors, output the functor number (based on lexicographic
order) as well in the RTTI data.
library/erlang_rtti_implementation.m:
Implement the functor numbering and type_ctor_desc changes.
Rename some procedures to distinguish between type_ctor_infos and
type_ctor_descs.
Fix some minor bugs.
library/construct.m:
Make get_functor_ordinal, get_functor_lex call the corresponding
procedures in erlang_rtti_implementation.
library/deconstruct.m:
Make deconstruct_du, functor_number, functor_number_cc
call the corresponding procedures in erlang_rtti_implementation.
library/type_desc.m:
Make type_ctor, type_ctor_and_args, make_type,
type_ctor_name_and_arity call the corresponding procedures in
erlang_rtti_implementation.
Fix the comparisons of type_ctor_descs which were not updated when the
calling convention of single output procedures was changed.
tests/hard_coded/construct_test.exp:
tests/hard_coded/construct_test.m:
Do additional tests on list and dummy types, which were not covered
previously.
Index: compiler/erl_rtti.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/erl_rtti.m,v
retrieving revision 1.16
diff -u -r1.16 erl_rtti.m
--- compiler/erl_rtti.m 20 Aug 2007 03:35:53 -0000 1.16
+++ compiler/erl_rtti.m 30 Aug 2007 05:27:41 -0000
@@ -126,29 +126,37 @@
:- func erlang_type_ctor_details_2(type_ctor_details) =
erlang_type_ctor_details.
-erlang_type_ctor_details_2(enum(_, Functors, _, _, IsDummy, _)) =
+erlang_type_ctor_details_2(enum(_, Functors, _, _, IsDummy, FunctorNums))
+ = Details :-
( IsDummy = yes ->
( Functors = [F] ->
- erlang_dummy(F ^ enum_name)
+ Details = erlang_dummy(F ^ enum_name)
;
unexpected(this_file, "dummy type with more than one functor")
)
;
- erlang_du(list.map(convert_enum_functor, Functors))
+ list.map_corresponding(convert_enum_functor, Functors, FunctorNums,
+ ErlFunctors),
+ Details = erlang_du(ErlFunctors)
).
erlang_type_ctor_details_2(foreign_enum(_, _, _, _, _)) =
sorry(this_file, "NYI foreign enumerations for Erlang.").
-erlang_type_ctor_details_2(du(_, Functors, _, _, _)) =
- erlang_du(list.map(convert_du_functor, Functors)).
+erlang_type_ctor_details_2(du(_, Functors, _, _, FunctorNums)) = Details :-
+ list.map_corresponding(convert_du_functor, Functors, FunctorNums,
+ ErlangFunctors),
+ Details = erlang_du(ErlangFunctors).
erlang_type_ctor_details_2(reserved(_, _, _, _, _, _)) =
% Reserved types are not supported on the Erlang backend.
unexpected(this_file, "erlang_type_ctor_details: reserved").
erlang_type_ctor_details_2(notag(_, NoTagFunctor)) = Details :-
NoTagFunctor = notag_functor(Name, TypeInfo, ArgName),
+ OrigArity = 1,
+ Ordinal = 0,
+ FunctorNum = 0,
ArgTypeInfo = convert_to_rtti_maybe_pseudo_type_info_or_self(TypeInfo),
ArgInfos = [du_arg_info(ArgName, ArgTypeInfo)],
- DUFunctor =
- erlang_du_functor(Name, 1, 1, erlang_atom_raw(Name), ArgInfos, no),
+ DUFunctor = erlang_du_functor(Name, OrigArity, Ordinal, FunctorNum,
+ erlang_atom_raw(Name), ArgInfos, no),
Details = erlang_du([DUFunctor]).
erlang_type_ctor_details_2(eqv(Type)) = erlang_eqv(Type).
erlang_type_ctor_details_2(builtin(Builtin)) = erlang_builtin(Builtin).
@@ -159,19 +167,24 @@
%
% Convert an enum_functor into the equivalent erlang_du_functor
%
-:- func convert_enum_functor(enum_functor) = erlang_du_functor.
+:- pred convert_enum_functor(enum_functor::in, int::in, erlang_du_functor::out)
+ is det.
-convert_enum_functor(enum_functor(Name, Ordinal)) =
- erlang_du_functor(Name, 0, Ordinal, erlang_atom_raw(Name), [], no).
+convert_enum_functor(EnumFunctor, FunctorNum, ErlangFunctor) :-
+ EnumFunctor = enum_functor(Name, Ordinal),
+ ErlangFunctor = erlang_du_functor(Name, 0, Ordinal, FunctorNum,
+ erlang_atom_raw(Name), [], no).
%
% Convert a du_functor into the equivalent erlang_du_functor
%
-:- func convert_du_functor(du_functor) = erlang_du_functor.
+:- pred convert_du_functor(du_functor::in, int::in, erlang_du_functor::out)
+ is det.
-convert_du_functor(du_functor(Name, Arity, Ordinal, _, ArgInfos, Exist)) =
- erlang_du_functor(Name, Arity,
- Ordinal, erlang_atom_raw(Name), ArgInfos, Exist).
+convert_du_functor(Functor, FunctorNum, ErlangFunctor) :-
+ Functor = du_functor(Name, Arity, Ordinal, _, ArgInfos, Exist),
+ ErlangFunctor = erlang_du_functor(Name, Arity, Ordinal, FunctorNum,
+ erlang_atom_raw(Name), ArgInfos, Exist).
:- func convert_to_rtti_maybe_pseudo_type_info_or_self(
rtti_maybe_pseudo_type_info) = rtti_maybe_pseudo_type_info_or_self.
Index: compiler/erlang_rtti.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/erlang_rtti.m,v
retrieving revision 1.5
diff -u -r1.5 erlang_rtti.m
--- compiler/erlang_rtti.m 7 Jun 2007 07:53:05 -0000 1.5
+++ compiler/erlang_rtti.m 30 Aug 2007 05:27:44 -0000
@@ -113,6 +113,9 @@
% The declaration order of the functor.
edu_ordinal :: int,
+ % The lexicographic order of the functor.
+ edu_lex :: int,
+
% erlang atom which represents the functor
% currently encoded version of name
% in the future maybe name_arity
Index: library/construct.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/library/construct.m,v
retrieving revision 1.37
diff -u -r1.37 construct.m
--- library/construct.m 20 Aug 2007 03:36:16 -0000 1.37
+++ library/construct.m 30 Aug 2007 05:27:44 -0000
@@ -361,6 +361,14 @@
get_functor_ordinal(TypeDesc, FunctorNumber) = Ordinal :-
get_functor_ordinal(TypeDesc, FunctorNumber, Ordinal).
+get_functor_ordinal(TypeDesc, FunctorNumber, Ordinal) :-
+ ( erlang_rtti_implementation.is_erlang_backend ->
+ erlang_rtti_implementation.get_functor_ordinal(TypeDesc, FunctorNumber,
+ Ordinal)
+ ;
+ private_builtin.sorry("get_functor_ordinal/3")
+ ).
+
:- pragma foreign_proc("C",
get_functor_ordinal(TypeDesc::in, FunctorNumber::in, Ordinal::out),
[will_not_call_mercury, thread_safe, promise_pure],
@@ -453,6 +461,14 @@
SUCCESS_INDICATOR = success;
}").
+get_functor_lex(TypeDesc, Ordinal) = FunctorNumber :-
+ ( erlang_rtti_implementation.is_erlang_backend ->
+ erlang_rtti_implementation.get_functor_lex(TypeDesc, Ordinal,
+ FunctorNumber)
+ ;
+ private_builtin.sorry("get_functor_lex/3")
+ ).
+
:- pragma foreign_proc("C",
get_functor_lex(TypeDesc::in, Ordinal::in) = (FunctorNumber::out),
[will_not_call_mercury, thread_safe, promise_pure],
Index: library/deconstruct.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/library/deconstruct.m,v
retrieving revision 1.46
diff -u -r1.46 deconstruct.m
--- library/deconstruct.m 25 Jul 2007 03:08:50 -0000 1.46
+++ library/deconstruct.m 30 Aug 2007 05:27:44 -0000
@@ -432,6 +432,21 @@
).
deconstruct_du(Term, NonCanon, FunctorNumber, Arity, Arguments) :-
+ ( erlang_rtti_implementation.is_erlang_backend ->
+ erlang_rtti_implementation.deconstruct(Term, NonCanon, _Functor,
+ FunctorNumber, Arity, Arguments)
+ ;
+ deconstruct_du_2(Term, NonCanon, FunctorNumber, Arity, Arguments)
+ ).
+
+:- pred deconstruct_du_2(T, noncanon_handling, functor_number_lex,
+ int, list(univ)).
+:- mode deconstruct_du_2(in, in(do_not_allow), out, out, out) is semidet.
+:- mode deconstruct_du_2(in, in(include_details_cc), out, out, out)
+ is cc_nondet.
+:- mode deconstruct_du_2(in, in, out, out, out) is cc_nondet.
+
+deconstruct_du_2(Term, NonCanon, FunctorNumber, Arity, Arguments) :-
( _ = construct.num_functors(type_of(Term)) ->
(
NonCanon = do_not_allow,
@@ -581,10 +596,21 @@
SUCCESS_INDICATOR = (FunctorNumber >= 0);
}").
-functor_number(_Term::in, _FunctorNumber::out, _Arity::out) :-
- private_builtin.sorry("deconstruct.functor_number").
-functor_number_cc(_Term::in, _FunctorNumber::out, _Arity::out) :-
- private_builtin.sorry("deconstruct.functor_number_cc").
+functor_number(Term::in, FunctorNumber::out, Arity::out) :-
+ ( erlang_rtti_implementation.is_erlang_backend ->
+ erlang_rtti_implementation.deconstruct(Term, do_not_allow,
+ _Functor, FunctorNumber, Arity, _Args)
+ ;
+ private_builtin.sorry("deconstruct.functor_number")
+ ).
+
+functor_number_cc(Term::in, FunctorNumber::out, Arity::out) :-
+ ( erlang_rtti_implementation.is_erlang_backend ->
+ erlang_rtti_implementation.deconstruct(Term, include_details_cc,
+ _Functor, FunctorNumber, Arity, _Args)
+ ;
+ private_builtin.sorry("deconstruct.functor_number_cc")
+ ).
%-----------------------------------------------------------------------------%
@@ -1017,7 +1043,7 @@
local_deconstruct(T, H, F, A, As) :-
( erlang_rtti_implementation.is_erlang_backend ->
- erlang_rtti_implementation.deconstruct(T, H, F, A, As)
+ erlang_rtti_implementation.deconstruct(T, H, F, _FN, A, As)
;
rtti_implementation.deconstruct(T, H, F, A, As)
).
Index: library/erlang_rtti_implementation.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/library/erlang_rtti_implementation.m,v
retrieving revision 1.16
diff -u -r1.16 erlang_rtti_implementation.m
--- library/erlang_rtti_implementation.m 24 Aug 2007 07:56:27 -0000 1.16
+++ library/erlang_rtti_implementation.m 30 Aug 2007 05:27:44 -0000
@@ -7,7 +7,7 @@
%-----------------------------------------------------------------------------%
%
% File: erlang_rtti_implementation.m.
-% Main author: petdr.
+% Main author: petdr, wangp.
% Stability: low.
%
% This file is intended to provide the RTTI implementation for the Erlang
@@ -42,17 +42,26 @@
:- pred compare_type_infos(comparison_result::out,
type_info::in, type_info::in) is det.
-:- pred type_ctor_and_args(type_info::in, type_ctor_info_evaled::out,
+:- pred type_ctor_info_and_args(type_info::in, type_ctor_info_evaled::out,
list(type_info)::out) is det.
-:- pred type_ctor_name_and_arity(type_ctor_info_evaled::in,
+:- pred type_ctor_desc(type_desc::in, type_ctor_desc::out) is det.
+
+:- pred type_ctor_desc_and_args(type_desc::in, type_ctor_desc::out,
+ list(type_desc)::out) is det.
+
+:- pred make_type_desc(type_ctor_desc::in, list(type_desc)::in,
+ type_desc::out) is semidet.
+
+:- pred type_ctor_desc_name_and_arity(type_ctor_desc::in,
string::out, string::out, int::out) is det.
-:- pred deconstruct(T, noncanon_handling, string, int, list(univ)).
-:- mode deconstruct(in, in(do_not_allow), out, out, out) is det.
-:- mode deconstruct(in, in(canonicalize), out, out, out) is det.
-:- mode deconstruct(in, in(include_details_cc), out, out, out) is cc_multi.
-:- mode deconstruct(in, in, out, out, out) is cc_multi.
+:- pred deconstruct(T, noncanon_handling, string, int, int, list(univ)).
+:- mode deconstruct(in, in(do_not_allow), out, out, out, out) is det.
+:- mode deconstruct(in, in(canonicalize), out, out, out, out) is det.
+:- mode deconstruct(in, in(include_details_cc), out, out, out, out)
+ is cc_multi.
+:- mode deconstruct(in, in, out, out, out, out) is cc_multi.
%-----------------------------------------------------------------------------%
%
@@ -67,6 +76,12 @@
int::out, list(type_desc.type_desc)::out, list(string)::out)
is semidet.
+:- pred get_functor_ordinal(type_desc.type_desc::in, int::in, int::out)
+ is semidet.
+
+:- pred get_functor_lex(type_desc.type_desc::in, int::in, int::out)
+ is semidet.
+
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
@@ -144,6 +159,18 @@
; etcr_ticket
.
+ % Values of type `type_desc' are represented the same way as values of
+ % type `type_info'.
+ %
+ % Values of type `type_ctor_desc' are NOT represented the same way as
+ % values of type `type_ctor_info'. The representations *are* in fact
+ % identical for fixed arity types, but they differ for higher order and
+ % tuple types. In that case they are one of the following:
+ %
+ % {pred, Arity},
+ % {func, Arity},
+ % {tuple, Arity}
+
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
@@ -318,18 +345,15 @@
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
-type_ctor_and_args(TypeInfo0, TypeCtorInfo, Args) :-
+type_ctor_info_and_args(TypeInfo0, TypeCtorInfo, Args) :-
TypeInfo = collapse_equivalences(TypeInfo0),
TypeCtorInfo = TypeInfo ^ type_ctor_info_evaled,
( type_ctor_is_variable_arity(TypeCtorInfo) ->
- Arity = TypeInfo ^ var_arity_type_info_arity,
- Args = list.map(
- func(L) = TypeInfo ^ var_arity_type_info_index(L), 1 .. Arity)
+ Args = get_var_arity_arg_type_infos(TypeInfo)
;
- Arity = TypeCtorInfo ^ type_ctor_arity,
- Args = list.map(func(L) = TypeInfo ^ type_info_index(L), 1 .. Arity)
+ Args = get_fixed_arity_arg_type_infos(TypeInfo)
).
-
+
:- pred type_ctor_is_variable_arity(type_ctor_info_evaled::in) is semidet.
type_ctor_is_variable_arity(TypeCtorInfo) :-
@@ -339,11 +363,203 @@
; TypeCtorRep = etcr_func
).
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+type_ctor_desc(TypeDesc, TypeCtorDesc) :-
+ type_ctor_desc_and_args(TypeDesc, TypeCtorDesc, _Args).
+
+type_ctor_desc_and_args(TypeDesc, TypeCtorDesc, ArgsDescs) :-
+ TypeInfo0 = type_info_from_type_desc(TypeDesc),
+ TypeInfo = collapse_equivalences(TypeInfo0),
+ TypeCtorInfo = TypeInfo ^ type_ctor_info_evaled,
+ TypeCtorRep = TypeCtorInfo ^ type_ctor_rep,
+ % Handle variable arity types.
+ ( TypeCtorRep = etcr_pred ->
+ Arity = TypeInfo ^ var_arity_type_info_arity,
+ TypeCtorDesc = make_pred_type_ctor_desc(Arity),
+ ArgInfos = get_var_arity_arg_type_infos(TypeInfo)
+
+ ; TypeCtorRep = etcr_func ->
+ Arity = TypeInfo ^ var_arity_type_info_arity,
+ TypeCtorDesc = make_func_type_ctor_desc(Arity),
+ ArgInfos = get_var_arity_arg_type_infos(TypeInfo)
+
+ ; TypeCtorRep = etcr_tuple ->
+ Arity = TypeInfo ^ var_arity_type_info_arity,
+ TypeCtorDesc = make_tuple_type_ctor_desc(Arity),
+ ArgInfos = get_var_arity_arg_type_infos(TypeInfo)
+ ;
+ % Handle fixed arity types.
+ TypeCtorDesc = make_fixed_arity_type_ctor_desc(TypeCtorInfo),
+ ArgInfos = get_fixed_arity_arg_type_infos(TypeInfo)
+ ),
+ ArgsDescs = type_descs_from_type_infos(ArgInfos).
+
+:- func make_pred_type_ctor_desc(int) = type_ctor_desc.
+
+:- pragma foreign_proc("Erlang",
+ make_pred_type_ctor_desc(Arity::in) = (TypeCtorDesc::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ TypeCtorDesc = {pred, Arity}
+").
+
+make_pred_type_ctor_desc(_) = _ :-
+ private_builtin.sorry("make_pred_type_ctor_desc").
+
+:- func make_func_type_ctor_desc(int) = type_ctor_desc.
+
+:- pragma foreign_proc("Erlang",
+ make_func_type_ctor_desc(Arity::in) = (TypeCtorDesc::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ TypeCtorDesc = {func, Arity}
+").
+
+make_func_type_ctor_desc(_) = _ :-
+ private_builtin.sorry("make_func_type_ctor_desc").
+
+:- func make_tuple_type_ctor_desc(int) = type_ctor_desc.
+
+:- pragma foreign_proc("Erlang",
+ make_tuple_type_ctor_desc(Arity::in) = (TypeCtorDesc::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ TypeCtorDesc = {tuple, Arity}
+").
+
+make_tuple_type_ctor_desc(_) = _ :-
+ private_builtin.sorry("make_tuple_type_ctor_desc").
+
+:- func make_fixed_arity_type_ctor_desc(type_ctor_info_evaled)
+ = type_ctor_desc.
+
+make_fixed_arity_type_ctor_desc(TypeCtorInfo) = TypeCtorDesc :-
+ % Fixed arity types have the same representations.
+ TypeCtorDesc = unsafe_cast(TypeCtorInfo).
+
+:- func type_info_from_type_desc(type_desc) = type_info.
+
+type_info_from_type_desc(TypeDesc) = TypeInfo :-
+ % They have the same representation.
+ TypeInfo = unsafe_cast(TypeDesc).
+
+:- func type_descs_from_type_infos(list(type_info)) = list(type_desc).
+
+type_descs_from_type_infos(TypeInfos) = TypeDescs :-
+ % They have the same representation.
+ TypeDescs = unsafe_cast(TypeInfos).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
-type_ctor_name_and_arity(TypeCtorInfo, ModuleName, Name, Arity) :-
+:- pragma foreign_proc("Erlang",
+ make_type_desc(TypeCtorDesc::in, ArgTypeDescs::in, TypeDesc::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ MakeVarArityTypeDesc =
+ (fun(TypeCtorInfo, Arity, ArgTypeInfos) ->
+ case Arity =:= length(ArgTypeInfos) of
+ true ->
+ TypeInfo =
+ list_to_tuple([TypeCtorInfo, Arity | ArgTypeDescs]),
+ {true, TypeInfo};
+ false ->
+ {false, null}
+ end
+ end),
+
+ case TypeCtorDesc of
+ % Handle the variable arity types.
+ {pred, Arity} ->
+ TCI = fun mercury__builtin:builtin__type_ctor_info_pred_0/0,
+ {SUCCESS_INDICATOR, TypeDesc} = MakeVarArityTypeDesc(TCI, Arity,
+ ArgTypeDescs);
+
+ {func, Arity} ->
+ TCI = fun mercury__builtin:builtin__type_ctor_info_func_0/0,
+ {SUCCESS_INDICATOR, TypeDesc} = MakeVarArityTypeDesc(TCI, Arity,
+ ArgTypeDescs);
+
+ {tuple, Arity} ->
+ TCI = fun mercury__builtin:builtin__type_ctor_info_tuple_0/0,
+ {SUCCESS_INDICATOR, TypeDesc} = MakeVarArityTypeDesc(TCI, Arity,
+ ArgTypeDescs);
+
+ % Handle fixed arity types.
+ TypeCtorInfo ->
+ ArgTypeInfos = ArgTypeDescs,
+ case
+ mercury__erlang_rtti_implementation:
+ 'ML_make_fixed_arity_type_info'(TypeCtorInfo, ArgTypeInfos)
+ of
+ {TypeInfo} ->
+ SUCCESS_INDICATOR = true,
+ % type_desc and type_info have same representation.
+ TypeDesc = TypeInfo;
+ fail ->
+ SUCCESS_INDICATOR = false,
+ TypeDesc = null
+ end
+ end
+").
+
+make_type_desc(_, _, _) :-
+ private_builtin.sorry("make_type_desc/3").
+
+:- pred make_fixed_arity_type_info(type_ctor_info_evaled::in,
+ list(type_info)::in, type_info::out) is semidet.
+
+:- pragma foreign_export("Erlang", make_fixed_arity_type_info(in, in, out),
+ "ML_make_fixed_arity_type_info").
+
+make_fixed_arity_type_info(TypeCtorInfo, ArgTypeInfos, TypeInfo) :-
+ TypeCtorInfo ^ type_ctor_arity = list.length(ArgTypeInfos),
+ TypeInfo = create_type_info(TypeCtorInfo, ArgTypeInfos).
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- pragma foreign_proc("Erlang",
+ type_ctor_desc_name_and_arity(TypeCtorDesc::in, ModuleName::out, Name::out,
+ Arity::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ case TypeCtorDesc of
+ {pred, Arity} ->
+ ModuleName = <<""builtin"">>,
+ Name = <<""pred"">>,
+ Arity = Arity;
+
+ {func, Arity} ->
+ ModuleName = <<""builtin"">>,
+ Name = <<""func"">>,
+ Arity = Arity;
+
+ {tuple, Arity} ->
+ ModuleName = <<""builtin"">>,
+ Name = <<""{}"">>,
+ Arity = Arity;
+
+ TypeCtorInfo ->
+ {ModuleName, Name, Arity} =
+ mercury__erlang_rtti_implementation:
+ 'ML_type_ctor_info_name_and_arity'(TypeCtorInfo)
+ end
+").
+
+type_ctor_desc_name_and_arity(_, _, _, _) :-
+ private_builtin.sorry("type_ctor_desc_name_and_arity/4").
+
+:- pred type_ctor_info_name_and_arity(type_ctor_info_evaled::in,
+ string::out, string::out, int::out) is det.
+
+:- pragma foreign_export("Erlang",
+ type_ctor_info_name_and_arity(in, out, out, out),
+ "ML_type_ctor_info_name_and_arity").
+
+type_ctor_info_name_and_arity(TypeCtorInfo, ModuleName, Name, Arity) :-
ModuleName = TypeCtorInfo ^ type_ctor_module_name,
Name = TypeCtorInfo ^ type_ctor_type_name,
Arity = TypeCtorInfo ^ type_ctor_arity.
@@ -351,27 +567,29 @@
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
-deconstruct(Term, NonCanon, Functor, Arity, Arguments) :-
+deconstruct(Term, NonCanon, Functor, FunctorNumber, Arity, Arguments) :-
TypeInfo = Term ^ type_info,
TypeCtorInfo = TypeInfo ^ type_ctor_info_evaled,
TypeCtorRep = TypeCtorInfo ^ type_ctor_rep,
deconstruct_2(Term, TypeInfo, TypeCtorInfo, TypeCtorRep, NonCanon,
- Functor, Arity, Arguments).
+ Functor, FunctorNumber, Arity, Arguments).
:- pred deconstruct_2(T, type_info, type_ctor_info_evaled,
- erlang_type_ctor_rep, noncanon_handling, string, int, list(univ)).
-:- mode deconstruct_2(in, in, in, in, in(do_not_allow), out, out, out) is det.
-:- mode deconstruct_2(in, in, in, in, in(canonicalize), out, out, out) is det.
+ erlang_type_ctor_rep, noncanon_handling, string, int, int, list(univ)).
+:- mode deconstruct_2(in, in, in, in, in(do_not_allow), out, out, out, out)
+ is det.
+:- mode deconstruct_2(in, in, in, in, in(canonicalize), out, out, out, out)
+ is det.
:- mode deconstruct_2(in, in, in, in,
- in(include_details_cc), out, out, out) is cc_multi.
-:- mode deconstruct_2(in, in, in, in, in, out, out, out) is cc_multi.
+ in(include_details_cc), out, out, out, out) is cc_multi.
+:- mode deconstruct_2(in, in, in, in, in, out, out, out, out) is cc_multi.
deconstruct_2(Term, TypeInfo, TypeCtorInfo, TypeCtorRep, NonCanon,
- Functor, Arity, Arguments) :-
+ Functor, FunctorNumber, Arity, Arguments) :-
(
TypeCtorRep = etcr_du,
FunctorReps = TypeCtorInfo ^ type_ctor_functors,
- FunctorRep = matching_du_functor(FunctorReps, Term),
+ matching_du_functor(FunctorReps, 0, Term, FunctorRep, FunctorNumber),
Functor = string.from_char_list(FunctorRep ^ edu_name),
Arity = FunctorRep ^ edu_orig_arity,
Arguments = list.map(
@@ -379,6 +597,7 @@
;
TypeCtorRep = etcr_dummy,
Functor = TypeCtorInfo ^ type_ctor_dummy_functor_name,
+ FunctorNumber = 0,
Arity = 0,
Arguments = []
;
@@ -386,10 +605,12 @@
ArgTypeInfo = TypeInfo ^ type_info_index(1),
( is_non_empty_list(TypeInfo, ArgTypeInfo, Term, H, T) ->
Functor = "[|]",
+ FunctorNumber = 1,
Arity = 2,
Arguments = [univ(H), univ(T)]
;
Functor = "[]",
+ FunctorNumber = 0,
Arity = 0,
Arguments = []
)
@@ -408,6 +629,7 @@
det_dynamic_cast(Term, Array),
Functor = "<<array>>",
+ FunctorNumber = 0,
Arity = array.size(Array),
Arguments = array.foldr(
(func(Elem, List) = [univ(Elem) | List]),
@@ -418,34 +640,39 @@
EqvTypeCtorInfo = EqvTypeInfo ^ type_ctor_info_evaled,
EqvTypeCtorRep = EqvTypeCtorInfo ^ type_ctor_rep,
deconstruct_2(Term, EqvTypeInfo, EqvTypeCtorInfo, EqvTypeCtorRep,
- NonCanon, Functor, Arity, Arguments)
+ NonCanon, Functor, FunctorNumber, Arity, Arguments)
;
TypeCtorRep = etcr_tuple,
Arity = TypeInfo ^ var_arity_type_info_arity,
Functor = "{}",
+ FunctorNumber = 0,
Arguments = list.map(get_tuple_arg(TypeInfo, Term), 1 .. Arity)
;
TypeCtorRep = etcr_int,
det_dynamic_cast(Term, Int),
Functor = string.int_to_string(Int),
+ FunctorNumber = 0,
Arity = 0,
Arguments = []
;
TypeCtorRep = etcr_float,
det_dynamic_cast(Term, Float),
Functor = float_to_string(Float),
+ FunctorNumber = 0,
Arity = 0,
Arguments = []
;
TypeCtorRep = etcr_char,
det_dynamic_cast(Term, Char),
Functor = term_io.quoted_char(Char),
+ FunctorNumber = 0,
Arity = 0,
Arguments = []
;
TypeCtorRep = etcr_string,
det_dynamic_cast(Term, String),
Functor = term_io.quoted_string(String),
+ FunctorNumber = 0,
Arity = 0,
Arguments = []
;
@@ -457,12 +684,14 @@
TypeCtorRep = etcr_stable_c_pointer,
det_dynamic_cast(Term, CPtr),
Functor = "stable_" ++ string.c_pointer_to_string(CPtr),
+ FunctorNumber = 0,
Arity = 0,
Arguments = []
;
TypeCtorRep = etcr_c_pointer,
det_dynamic_cast(Term, CPtr),
Functor = string.c_pointer_to_string(CPtr),
+ FunctorNumber = 0,
Arity = 0,
Arguments = []
;
@@ -493,18 +722,21 @@
;
NonCanon = canonicalize,
Functor = Name,
+ FunctorNumber = 0,
Arity = 0,
Arguments = []
;
% XXX this needs to be fixed
NonCanon = include_details_cc,
Functor = Name,
+ FunctorNumber = 0,
Arity = 0,
Arguments = []
)
;
TypeCtorRep = etcr_foreign,
Functor = "<<foreign>>",
+ FunctorNumber = 0,
Arity = 0,
Arguments = []
;
@@ -521,19 +753,22 @@
).
%
- % matching_du_functor(Functors, Term)
+ % matching_du_functor(FunctorReps, Index, Term, FunctorRep, FunctorNumber)
%
% finds the erlang_du_functor in the list Functors which describes
% the given Term.
%
-:- func matching_du_functor(list(erlang_du_functor), T) = erlang_du_functor.
+:- pred matching_du_functor(list(erlang_du_functor)::in, int::in, T::in,
+ erlang_du_functor::out, int::out) is det.
-matching_du_functor([], _) = func_error(this_file ++ " matching_du_functor/2").
-matching_du_functor([F | Fs], T) =
+matching_du_functor([], _, _, _, _) :-
+ error(this_file ++ " matching_du_functor/2").
+matching_du_functor([F | Fs], Index, T, Functor, FunctorNumber) :-
( matches_du_functor(T, F) ->
- F
+ Functor = F,
+ FunctorNumber = Index
;
- matching_du_functor(Fs, T)
+ matching_du_functor(Fs, Index + 1, T, Functor, FunctorNumber)
).
%
@@ -685,7 +920,8 @@
%-----------------------------------------------------------------------------%
num_functors(TypeDesc) = NumFunctors :-
- num_functors(unsafe_cast(TypeDesc), yes(NumFunctors)).
+ TypeInfo = type_info_from_type_desc(TypeDesc),
+ num_functors(TypeInfo, yes(NumFunctors)).
:- pred num_functors(type_info::in, maybe(int)::out) is det.
@@ -740,10 +976,12 @@
get_functor(TypeDesc, FunctorNum, Name, Arity, ArgTypes) :-
get_functor_with_names(TypeDesc, FunctorNum, Name, Arity, ArgTypes, _).
-get_functor_with_names(TypeDesc, FunctorNum, Name, Arity, ArgTypes, ArgNames) :-
- MaybeResult = get_functor_with_names(unsafe_cast(TypeDesc), FunctorNum),
+get_functor_with_names(TypeDesc, FunctorNum, Name, Arity, ArgTypeDescs,
+ ArgNames) :-
+ TypeInfo = type_info_from_type_desc(TypeDesc),
+ MaybeResult = get_functor_with_names(TypeInfo, FunctorNum),
MaybeResult = yes({Name, Arity, ArgTypeInfos, ArgNames}),
- ArgTypes = list.map(unsafe_cast, ArgTypeInfos).
+ ArgTypeDescs = type_descs_from_type_infos(ArgTypeInfos).
:- func get_functor_with_names(type_info, int) =
maybe({string, int, list(type_info), list(string)}).
@@ -754,7 +992,7 @@
(
TypeCtorRep = etcr_du,
FunctorReps = TypeCtorInfo ^ type_ctor_functors,
- ( list.index0(FunctorReps, NumFunctor, FunctorRep) ->
+ ( matching_du_functor_number(FunctorReps, NumFunctor, FunctorRep) ->
MaybeExistInfo = FunctorRep ^ edu_exist_info,
(
MaybeExistInfo = yes(_),
@@ -763,12 +1001,11 @@
MaybeExistInfo = no,
ArgInfos = FunctorRep ^ edu_arg_infos,
- list.foldl2(
- (pred(ArgInfo::in, T0::in, T::out, N0::in, N::out) is det :-
+ list.map2(
+ (pred(ArgInfo::in, ArgTypeInfo::out, ArgName::out) is det :-
MaybePTI = ArgInfo ^ du_arg_type,
Info = yes({TypeInfo, no : pti_info(int)}),
ArgTypeInfo = type_info(Info, MaybePTI),
- T = [ArgTypeInfo | T0],
MaybeArgName = ArgInfo ^ du_arg_name,
(
@@ -777,14 +1014,11 @@
;
MaybeArgName = no,
ArgName = ""
- ),
- N = [ArgName | N0]
- ), ArgInfos, [], RevArgTypes, [], RevArgNames),
+ )
+ ), ArgInfos, ArgTypes, ArgNames),
Name = string.from_char_list(FunctorRep ^ edu_name),
Arity = FunctorRep ^ edu_orig_arity,
- ArgTypes = list.reverse(RevArgTypes),
- ArgNames = list.reverse(RevArgNames),
Result = yes({Name, Arity, ArgTypes, ArgNames})
)
;
@@ -799,21 +1033,21 @@
Result = yes({Name, Arity, ArgTypes, ArgNames})
;
TypeCtorRep = etcr_tuple,
- type_ctor_and_args(TypeInfo, _TypeCtorInfo, ArgTypes),
+ type_ctor_info_and_args(TypeInfo, _TypeCtorInfo, ArgTypes),
Name = "{}",
Arity = list.length(ArgTypes),
ArgNames = list.duplicate(Arity, ""),
Result = yes({Name, Arity, ArgTypes, ArgNames})
;
TypeCtorRep = etcr_list,
- ( NumFunctor = 1 ->
+ ( NumFunctor = 0 ->
Name = "[]",
Arity = 0,
ArgTypes = [],
ArgNames = [],
Result = yes({Name, Arity, ArgTypes, ArgNames})
- ; NumFunctor = 2 ->
+ ; NumFunctor = 1 ->
ArgTypeInfo = TypeInfo ^ type_info_index(1),
Name = "[|]",
@@ -855,10 +1089,83 @@
error("num_functors: type_ctor_rep not handled")
).
+get_functor_ordinal(TypeDesc, FunctorNum, Ordinal) :-
+ TypeInfo = type_info_from_type_desc(TypeDesc),
+ TypeCtorInfo = TypeInfo ^ type_ctor_info_evaled,
+ TypeCtorRep = TypeCtorInfo ^ type_ctor_rep,
+ (
+ TypeCtorRep = etcr_du,
+ FunctorReps = TypeCtorInfo ^ type_ctor_functors,
+ matching_du_functor_number(FunctorReps, FunctorNum, FunctorRep),
+ Ordinal = FunctorRep ^ edu_ordinal
+ ;
+ TypeCtorRep = etcr_dummy,
+ FunctorNum = 0,
+ Ordinal = 0
+ ;
+ TypeCtorRep = etcr_list,
+ (
+ Ordinal = 0,
+ FunctorNum = 0
+ ;
+ Ordinal = 1,
+ FunctorNum = 1
+ )
+ ;
+ TypeCtorRep = etcr_tuple,
+ FunctorNum = 0,
+ Ordinal = 0
+ ).
+
+get_functor_lex(TypeDesc, Ordinal, FunctorNum) :-
+ TypeInfo = type_info_from_type_desc(TypeDesc),
+ TypeCtorInfo = TypeInfo ^ type_ctor_info_evaled,
+ TypeCtorRep = TypeCtorInfo ^ type_ctor_rep,
+ (
+ TypeCtorRep = etcr_du,
+ FunctorReps = TypeCtorInfo ^ type_ctor_functors,
+ matching_du_ordinal(FunctorReps, Ordinal, FunctorRep),
+ FunctorNum = FunctorRep ^ edu_lex
+ ;
+ TypeCtorRep = etcr_dummy,
+ FunctorNum = 0,
+ Ordinal = 0
+ ;
+ TypeCtorRep = etcr_list,
+ (
+ Ordinal = 0,
+ FunctorNum = 0
+ ;
+ Ordinal = 1,
+ FunctorNum = 1
+ )
+ ;
+ TypeCtorRep = etcr_tuple,
+ Ordinal = 0,
+ FunctorNum = 0
+ ).
+:- pred matching_du_ordinal(list(erlang_du_functor)::in, int::in,
+ erlang_du_functor::out) is semidet.
+matching_du_ordinal(Fs, Ordinal, Functor) :-
+ list.index0(Fs, Ordinal, Functor),
+ % Sanity check.
+ ( Functor ^ edu_ordinal = Ordinal ->
+ true
+ ;
+ error(this_file ++ " matching_du_ordinal/3")
+ ).
+:- pred matching_du_functor_number(list(erlang_du_functor)::in, int::in,
+ erlang_du_functor::out) is semidet.
+matching_du_functor_number([F | Fs], FunctorNum, Functor) :-
+ ( F ^ edu_lex = FunctorNum ->
+ Functor = F
+ ;
+ matching_du_functor_number(Fs, FunctorNum, Functor)
+ ).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
@@ -911,7 +1218,7 @@
% We evaluate the thunk to get the actual type_ctor_info data.
%
if
- is_function(TypeInfo) ->
+ is_function(TypeInfo, 0) ->
TypeCtorInfo = TypeInfo();
true ->
FirstElement = element(?ML_ti_type_ctor_info, TypeInfo),
@@ -970,6 +1277,35 @@
unsafe_type_info_index(_, _) = type_info :-
det_unimplemented("unsafe_type_info_index").
+:- func get_fixed_arity_arg_type_infos(type_info) = list(type_info).
+
+:- pragma foreign_proc("Erlang",
+ get_fixed_arity_arg_type_infos(TypeInfo::in) = (Args::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ if
+ is_tuple(TypeInfo) ->
+ [_TypeCtorInfo | Args] = tuple_to_list(TypeInfo);
+ is_function(TypeInfo, 0) ->
+ Args = [] % zero arity type_info
+ end
+").
+
+get_fixed_arity_arg_type_infos(_) = _ :-
+ private_builtin.sorry("get_fixed_arity_arg_type_infos").
+
+:- func get_var_arity_arg_type_infos(type_info) = list(type_info).
+
+:- pragma foreign_proc("Erlang",
+ get_var_arity_arg_type_infos(TypeInfo::in) = (Args::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ Args = lists:nthtail(?ML_ti_var_arity, tuple_to_list(TypeInfo))
+").
+
+get_var_arity_arg_type_infos(_) = _ :-
+ private_builtin.sorry("get_var_arity_arg_type_infos").
+
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
@@ -1339,6 +1675,7 @@
edu_name :: list(char),
edu_orig_arity :: int,
edu_ordinal :: int,
+ edu_lex :: int,
edu_rep :: erlang_atom,
edu_arg_infos :: list(du_arg_info),
edu_exist_info :: maybe(exist_info)
Index: library/type_desc.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/library/type_desc.m,v
retrieving revision 1.51
diff -u -r1.51 type_desc.m
--- library/type_desc.m 24 Aug 2007 04:15:29 -0000 1.51
+++ library/type_desc.m 30 Aug 2007 05:27:46 -0000
@@ -209,6 +209,7 @@
:- import_module require.
:- import_module string.
+:- use_module erlang_rtti_implementation.
:- use_module rtti_implementation.
:- pragma foreign_decl("C", "
@@ -580,6 +581,13 @@
TypeCtor = (MR_Word) MR_make_type_ctor_desc(type_info, type_ctor_info);
}").
+type_ctor(TypeDesc) = TypeCtorDesc :-
+ ( erlang_rtti_implementation.is_erlang_backend ->
+ erlang_rtti_implementation.type_ctor_desc(TypeDesc, TypeCtorDesc)
+ ;
+ private_builtin.sorry("type_ctor/1")
+ ).
+
:- pragma foreign_proc("C",
pseudo_type_ctor(PseudoTypeInfo::in) = (TypeCtor::out),
[will_not_call_mercury, thread_safe, promise_pure, will_not_modify_trail],
@@ -641,20 +649,17 @@
}
").
-:- pragma foreign_proc("Erlang",
- type_ctor_and_args(TypeDesc::in, TypeCtorDesc::out, ArgTypes::out),
- [may_call_mercury, thread_safe, promise_pure, terminates],
-"
- {TypeCtorDesc, ArgTypes} =
- mercury__erlang_rtti_implementation:type_ctor_and_args_3_p_0(TypeDesc)
-").
-
type_ctor_and_args(TypeDesc::in, TypeCtorDesc::out, ArgTypes::out) :-
- rtti_implementation.type_ctor_and_args(
- rtti_implementation.unsafe_cast(TypeDesc),
- TypeCtorDesc0, ArgTypes0),
- TypeCtorDesc = rtti_implementation.unsafe_cast(TypeCtorDesc0),
- ArgTypes = rtti_implementation.unsafe_cast(ArgTypes0).
+ ( erlang_rtti_implementation.is_erlang_backend ->
+ erlang_rtti_implementation.type_ctor_desc_and_args(TypeDesc,
+ TypeCtorDesc, ArgTypes)
+ ;
+ rtti_implementation.type_ctor_and_args(
+ rtti_implementation.unsafe_cast(TypeDesc),
+ TypeCtorDesc0, ArgTypes0),
+ TypeCtorDesc = rtti_implementation.unsafe_cast(TypeCtorDesc0),
+ ArgTypes = rtti_implementation.unsafe_cast(ArgTypes0)
+ ).
:- pragma foreign_proc("C",
pseudo_type_ctor_and_args(PseudoTypeDesc::in, TypeCtorDesc::out,
@@ -741,6 +746,17 @@
MR_restore_transient_registers();
}").
+make_type(TypeCtorDesc::in, ArgTypes::in) = (TypeDesc::out) :-
+ ( erlang_rtti_implementation.is_erlang_backend ->
+ erlang_rtti_implementation.make_type_desc(TypeCtorDesc, ArgTypes,
+ TypeDesc)
+ ;
+ private_builtin.sorry("make_type/2")
+ ).
+
+make_type(_TypeCtorDesc::out, _ArgTypes::out) = (_TypeDesc::in) :-
+ private_builtin.sorry("make_type/2").
+
:- pragma foreign_proc("C",
type_ctor_name_and_arity(TypeCtorDesc::in, TypeCtorModuleName::out,
TypeCtorName::out, TypeCtorArity::out),
@@ -789,27 +805,16 @@
TypeCtorArity = ((java.lang.Integer) result[2]).intValue();
").
-:- pragma foreign_proc("Erlang",
- type_ctor_name_and_arity(TypeCtorDesc0::in, TypeCtorModuleName::out,
- TypeCtorName::out, TypeCtorArity::out),
- [will_not_call_mercury, thread_safe, promise_pure],
-"
- if
- is_function(TypeCtorDesc0) ->
- TypeCtorDesc = TypeCtorDesc0();
- true ->
- TypeCtorDesc = TypeCtorDesc0
- end,
- {TypeCtorModuleName, TypeCtorName, TypeCtorArity} =
- mercury__erlang_rtti_implementation:
- type_ctor_name_and_arity_4_p_0(TypeCtorDesc)
-").
-
type_ctor_name_and_arity(TypeCtorDesc::in, ModuleName::out,
TypeCtorName::out, TypeCtorArity::out) :-
- rtti_implementation.type_ctor_name_and_arity(
- rtti_implementation.unsafe_cast(TypeCtorDesc),
- ModuleName, TypeCtorName, TypeCtorArity).
+ ( erlang_rtti_implementation.is_erlang_backend ->
+ erlang_rtti_implementation.type_ctor_desc_name_and_arity(TypeCtorDesc,
+ ModuleName, TypeCtorName, TypeCtorArity)
+ ;
+ rtti_implementation.type_ctor_name_and_arity(
+ rtti_implementation.unsafe_cast(TypeCtorDesc),
+ ModuleName, TypeCtorName, TypeCtorArity)
+ ).
%-----------------------------------------------------------------------------%
@@ -911,24 +916,24 @@
X = eval_if_function(X0),
Y = eval_if_function(Y0),
if
- X =:= Y -> {{'='}};
- X < Y -> {{'<'}};
- true -> {{'>'}}
+ X =:= Y -> {'='};
+ X < Y -> {'<'};
+ true -> {'>'}
end.
'__Compare____type_ctor_desc_0_0'(X0, Y0) ->
X = eval_if_function(X0),
Y = eval_if_function(Y0),
if
- X =:= Y -> {{'='}};
- X < Y -> {{'<'}};
- true -> {{'>'}}
+ X =:= Y -> {'='};
+ X < Y -> {'<'};
+ true -> {'>'}
end.
'__Compare____pseudo_type_desc_0_0'(_, _) ->
throw(""foreign code for comparing pseudo_type_desc"").
- eval_if_function(X) when is_function(X) -> X();
+ eval_if_function(X) when is_function(X, 0) -> X();
eval_if_function(X) when is_tuple(X) ->
list_to_tuple([eval_if_function(E) || E <- tuple_to_list(X)]);
eval_if_function(X) -> X.
Index: tests/hard_coded/construct_test.exp
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/hard_coded/construct_test.exp,v
retrieving revision 1.6
diff -u -r1.6 construct_test.exp
--- tests/hard_coded/construct_test.exp 15 Feb 2007 00:41:51 -0000 1.6
+++ tests/hard_coded/construct_test.exp 30 Aug 2007 05:27:47 -0000
@@ -150,6 +150,11 @@
0 - {}/4 [_, _, _, _] ordinal: 0 lex: 0
+2 functors in this type
+1 - [|]/2 [_, _] ordinal: 1 lex: 1
+0 - []/0 [] ordinal: 0 lex: 0
+
+
TESTING OTHER TYPES
1 functors in this type
@@ -176,6 +181,10 @@
1 functors in this type
+0 - dummy/0 [] ordinal: 0 lex: 0
+
+
+1 functors in this type
0 - xyzzy/1 [f21name] ordinal: 0 lex: 0
Index: tests/hard_coded/construct_test.m
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/hard_coded/construct_test.m,v
retrieving revision 1.6
diff -u -r1.6 construct_test.m
--- tests/hard_coded/construct_test.m 5 Jan 2007 02:19:44 -0000 1.6
+++ tests/hard_coded/construct_test.m 30 Aug 2007 05:27:47 -0000
@@ -29,6 +29,8 @@
:- type no_tag ---> qwerty(qwerty_field :: int).
+:- type dummy ---> dummy.
+
:- type exist_type ---> some [T] xyzzy(f21name :: T).
%----------------------------------------------------------------------------%
@@ -284,6 +286,9 @@
% test tuples
test_all({1, "a", 'a', {4, 'd'}}), newline,
+ % test lists
+ test_all([1, 2, 3, 4]), newline,
+
newline.
% Note: testing abstract types is always going to have results
@@ -308,6 +313,9 @@
% a no tag type
test_all(qwerty(4)), newline,
+ % a dummy type
+ test_all(dummy), newline,
+
% an existential type:
{ ExistVal = 'new xyzzy'(8) },
test_all(ExistVal), newline.
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to: mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions: mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------
More information about the reviews
mailing list