Files
mercury/browser/term_rep.m
Mark Brown d465fa53cb Update the COPYING.LIB file and references to it.
Discussion of these changes can be found on the Mercury developers
mailing list archives from June 2018.

COPYING.LIB:
    Add a special linking exception to the LGPL.

*:
    Update references to COPYING.LIB.

    Clean up some minor errors that have accumulated in copyright
    messages.
2018-06-09 17:43:12 +10:00

192 lines
5.9 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 1999-2007 The University of Melbourne.
% Copyright (C) 2015, 2017-2018 The Mercury team.
% This file is distributed under the terms specified in COPYING.LIB.
%---------------------------------------------------------------------------%
%
% File: term_rep.m.
% Author: Ian MacLarty.
%
% This module implements an abstract type, term_rep, values of which are the
% representation of some other value. Constructing a representation from a
% term is cc_multi, but then doing comparisons on the representation is
% deterministic.
%
% This is useful when we only want to consider the representation of a term
% and don't care about it's actual value.
%
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- module mdb.term_rep.
:- interface.
:- import_module mdbcomp.
:- import_module mdbcomp.program_representation.
:- import_module univ.
%---------------------------------------------------------------------------%
:- type term_rep.
:- pred univ_to_rep(univ::in, term_rep::out) is cc_multi.
:- pred rep_to_univ(term_rep::in, univ::out) is det.
:- pred deref_path(term_rep::in, term_path::in, term_rep::out) is semidet.
% argument(Term, N, Subterm):
%
% True iff Subterm is the Nth argument of Term.
%
:- pred argument(term_rep::in, int::in, term_rep::out) is semidet.
% field_pos(FieldName, Term, N):
%
% True iff argument N of Term has the name FieldName.
%
:- pred field_pos(string::in, term_rep::in, int::out) is semidet.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
:- import_module mdb.declarative_debugger.
:- import_module construct.
:- import_module deconstruct.
:- import_module exception.
:- import_module int.
:- import_module list.
:- import_module maybe.
:- import_module type_desc.
%---------------------------------------------------------------------------%
:- type term_rep
---> term_rep(univ)
where
equality is term_rep_equal,
comparison is term_rep_compare.
:- pred term_rep_equal(term_rep::in, term_rep::in) is semidet.
:- pragma terminates(term_rep_equal/2).
term_rep_equal(Rep1, Rep2) :-
promise_equivalent_solutions [Result] (
comp_rep_2(Rep1, Rep2, Result)
),
Result = (=).
:- pred comp_rep_2(term_rep::in, term_rep::in, builtin.comparison_result::uo)
is cc_multi.
comp_rep_2(Rep1, Rep2, Result) :-
builtin.compare_representation(Result, Rep1, Rep2).
:- pred term_rep_compare(builtin.comparison_result::uo, term_rep::in,
term_rep::in) is det.
:- pragma terminates(term_rep_compare/3).
term_rep_compare(Result, Rep1, Rep2) :-
promise_equivalent_solutions [Result] (
comp_rep_2(Rep1, Rep2, Result)
).
univ_to_rep(Univ0, term_rep(Univ)) :-
cc_multi_equal(Univ0, Univ).
rep_to_univ(Rep, Univ) :-
promise_equivalent_solutions [Univ] (
Rep = term_rep(Univ)
).
deref_path(Term, Path, SubTerm):-
(
Path = [],
SubTerm = Term
;
Path = [Head | Tail],
argument(Term, Head, NextSubTerm),
deref_path(NextSubTerm, Tail, SubTerm)
).
argument(Term, N, Arg) :-
% There is only one representation of a subterm, given
% the representation of the containing term and a term path.
promise_equivalent_solutions [MaybeArg] (
rep_to_univ(Term, Univ),
% Argument indexes in the term path start from one, but the argument
% function wants argument indexes to start from zero.
arg_cc(univ_value(Univ), N - 1, MaybeSubUniv),
(
MaybeSubUniv = arg(SubValue),
univ_to_rep(univ(SubValue), Arg0),
MaybeArg = yes(Arg0)
;
MaybeSubUniv = no_arg,
MaybeArg = no
)
),
MaybeArg = yes(Arg).
field_pos(FieldName, Term, Pos) :-
% There is only one or zero positions of a field
% given a representation of a term and the field name.
promise_equivalent_solutions [MaybePos] (
rep_to_univ(Term, Univ),
Value = univ_value(Univ),
deconstruct(Value, include_details_cc, Functor, Arity, _Args),
Type = type_of(Value),
( if NumFunctors = num_functors(Type) then
find_functor(1, NumFunctors, Type, Functor, Arity,
MaybeFunctorNum)
else
MaybeFunctorNum = no
),
(
MaybeFunctorNum = yes(FunctorNum),
( if
get_functor_with_names(Type, FunctorNum - 1,
_FunctorName, _Arity, _ArgTypes, ArgNames)
then
( if
list.index1_of_first_occurrence(ArgNames, yes(FieldName),
Pos0)
then
MaybePos = yes(Pos0)
else
MaybePos = no
)
else
throw(internal_error("field_pos",
"get_functor_with_names couldn't find functor"))
)
;
MaybeFunctorNum = no,
throw(internal_error("field_pos",
"find_functor couldn't find functor"))
)
),
MaybePos = yes(Pos).
:- pred find_functor(int::in, int::in, type_desc::in, string::in, int::in,
maybe(int)::out) is det.
find_functor(Current, NumFunctors, Type, FunctorName, Arity,
MaybeFunctorNum) :-
( if Current =< NumFunctors then
( if get_functor(Type, Current - 1, FunctorName, Arity, _) then
MaybeFunctorNum = yes(Current)
else
find_functor(Current + 1, NumFunctors, Type,
FunctorName, Arity, MaybeFunctorNum)
)
else
MaybeFunctorNum = no
).