%--------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%--------------------------------------------------%
% Copyright (C) 2002-2007 The University of Melbourne.
% Copyright (C) 2014-2015, 2017-2022, 2025 The Mercury team.
% This file is distributed under the terms specified in COPYING.LIB.
%--------------------------------------------------%
%
% File: deconstruct.m.
% Main author: zs.
% Stability: high.
%
%--------------------------------------------------%
%--------------------------------------------------%
:- module deconstruct.
:- interface.
:- import_module construct.
:- import_module list.
:- import_module maybe.
:- import_module univ.
%--------------------------------------------------%
% Values of type noncanon_handling are intended to control how
% predicates that deconstruct terms behave when they find that
% the term they are about to deconstruct is of a noncanonical type,
% i.e. of a type in which a single logical value may have more than one
% concrete representation.
%
% The value `do_not_allow' means that in such circumstances the
% predicate should cause a runtime abort.
%
% The value `canonicalize' means that in such circumstances the
% predicate should return a constant giving the identity of the type,
% regardless of the actual value of the term.
%
% The value `include_details_cc' means that in such circumstances
% the predicate should proceed as if the term were of a canonical type.
% Use of this option requires a committed choice context.
:- type noncanon_handling
---> do_not_allow
; canonicalize
; include_details_cc.
:- inst do_not_allow for noncanon_handling/0
---> do_not_allow.
:- inst canonicalize for noncanon_handling/0
---> canonicalize.
:- inst include_details_cc for noncanon_handling/0
---> include_details_cc.
:- inst canonicalize_or_do_not_allow for noncanon_handling/0
---> do_not_allow
; canonicalize.
:- inst do_not_allow_or_include_details_cc for noncanon_handling/0
---> do_not_allow
; include_details_cc.
% functor, argument and deconstruct and their variants take any type
% (including univ), and return representation information for that type.
%
% The string representation of the functor that these predicates
% return is:
%
% - for user defined types with standard equality, the functor
% that is given in the type definition. For lists, this means
% the functors [|]/2 and []/0 are used, even if the list uses
% the [....] shorthand.
% - for user-defined types with user-defined equality, the
% functor will be of the form <<module.type/arity>>, except
% with include_details_cc, in which case the type will be
% handled as if it had standard equality.
% - for integers, the string is a base 10 number;
% positive integers have no sign.
% - for finite floats, the string is a base 10 floating point number;
% positive floating point numbers have no sign;
% for infinite floats, the string "infinity" or "-infinity".
% - for strings, the string, inside double quotation marks using
% backslash escapes if necessary and backslash or octal escapes for
% all characters for which char.is_control/1 is true.
% - for characters, the character inside single quotation marks using
% a backslash escape if necessary and a backslash or octal escape for
% for all characters for which char.is_control/1 is true.
% - for predicates, the string <<predicate>>, and for functions,
% the string <<function>>, except with include_details_cc,
% in which case it will be the predicate or function name.
% (The predicate or function name will be artificial for
% predicate and function values created by lambda expressions.)
% - for tuples, the string {}.
% - for arrays, the string <<array>>.
% - for c_pointers, the string c_pointer(0xXXXX) where XXXX is the
% hexadecimal representation of the pointer.
% - for foreign types, a string of the form <<foreign(Name, Rep)>> where
% Name is the type's Mercury name and Rep is a target language specific
% representation of the term's value.
% - for bitmaps, the bitmap converted to a length and a
% hexadecimal string inside angle brackets and quotes of the
% form """<[0-9]:[0-9A-F]*>""".
%
% The arity that these predicates return is:
%
% - for user defined types with standard equality, the arity
% of the functor.
% - for user defined types with user-defined equality, zero,
% except with include_details_cc, in which case the type
% will be handled as if it had standard equality.
% - for integers, zero.
% - for floats, zero.
% - for strings, zero.
% - for characters, zero.
% - for predicates and functions, zero, except with
% include_details_cc, in which case it will be the number of
% arguments hidden in the closure.
% - for tuples, the number of elements in the tuple.
% - for arrays, the number of elements in the array.
% - for c_pointers, zero.
% - for foreign types, zero.
% - for bitmaps, zero.
%
% Note that in the current University of Melbourne implementation,
% the implementations of these predicates depart from the above
% specification in that with --high-level-code, they do not
% deconstruct predicate- and function-valued terms even with
% include_details_cc; instead, they return <<predicate>> or
% <<function>> (in both cases with arity zero) as appropriate.
% functor(Data, NonCanon, Functor, Arity)
%
% Given a data item (Data), binds Functor to a string representation
% of the functor and Arity to the arity of this data item.
%
:- pred functor(T, noncanon_handling, string, int).
:- mode functor(in, in(do_not_allow), out, out) is det.
:- mode functor(in, in(canonicalize), out, out) is det.
:- mode functor(in, in(include_details_cc), out, out) is cc_multi.
:- mode functor(in, in, out, out) is cc_multi.
% functor_number(Data, FunctorNumber, Arity)
%
% Given a data item, return the number of the functor,
% suitable for use by construct.construct, and the arity.
% Fail if the item does not have a discriminated union type.
% Cause a runtime abort if the type has user-defined equality.
%
:- pred functor_number(T::in, functor_number_lex::out, int::out) is semidet.
% functor_number_cc(Data, FunctorNumber, Arity)
%
% Given a data item, return the number of the functor,
% suitable for use by construct.construct, and the arity.
% Fail if the item does not have a discriminated union type.
% Do not cause a runtime abort if the type has user-defined equality.
%
:- pred functor_number_cc(T::in, functor_number_lex::out,
int::out) is cc_nondet.
% arg(Data, NonCanon, Index, Argument)
%
% Given a data item (Data) and an argument index (Index), starting
% at 0 for the first argument, binds Argument to that argument of
% the functor of the data item. If the argument index is out of range
% -- that is, greater than or equal to the arity of the functor or
% lower than 0 -- then the call fails.
%
% Note that this predicate only returns an answer when NonCanon is
% do_not_allow or canonicalize. If you need the include_details_cc
% behaviour use deconstruct.arg_cc/3.
%
:- some [ArgT] pred arg(T, noncanon_handling, int, ArgT).
:- mode arg(in, in(do_not_allow), in, out) is semidet.
:- mode arg(in, in(canonicalize), in, out) is semidet.
:- mode arg(in, in(canonicalize_or_do_not_allow), in, out) is semidet.
:- type maybe_arg
---> some [T] arg(T)
; no_arg.
% arg_cc/3 is similar to arg/4, except that it handles arguments with
% non-canonical types. The possible non-existence of an argument is
% encoded using a maybe type.
%
:- pred arg_cc(T::in, int::in, maybe_arg::out) is cc_multi.
% named_arg(Data, NonCanon, Name, Argument)
%
% Same as arg/4, except the chosen argument is specified by giving
% its name rather than its position. If Data has no argument with that
% name, named_arg fails.
%
:- some [ArgT] pred named_arg(T, noncanon_handling, string, ArgT).
:- mode named_arg(in, in(do_not_allow), in, out) is semidet.
:- mode named_arg(in, in(canonicalize), in, out) is semidet.
:- mode named_arg(in, in(canonicalize_or_do_not_allow), in, out) is semidet.
% named_arg_cc/3 is similar to named_arg/4, except that it handles
% arguments with non-canonical types.
%
:- pred named_arg_cc(T::in, string::in, maybe_arg::out) is cc_multi.
% det_arg(Data, NonCanon, Index, Argument)
%
% Same as arg/4, except that for cases where arg/4 would fail,
% det_arg/4 will throw an exception.
%
:- some [ArgT] pred det_arg(T, noncanon_handling, int, ArgT).
:- mode det_arg(in, in(do_not_allow), in, out) is det.
:- mode det_arg(in, in(canonicalize), in, out) is det.
:- mode det_arg(in, in(include_details_cc), in, out) is cc_multi.
:- mode det_arg(in, in, in, out) is cc_multi.
% det_named_arg(Data, NonCanon, Name, Argument)
%
% Same as named_arg/4, except that for cases where named_arg/4 would fail,
% det_named_arg/4 will throw an exception.
%
:- some [ArgT] pred det_named_arg(T, noncanon_handling, string, ArgT).
:- mode det_named_arg(in, in(do_not_allow), in, out) is det.
:- mode det_named_arg(in, in(canonicalize), in, out) is det.
:- mode det_named_arg(in, in(include_details_cc), in, out) is cc_multi.
:- mode det_named_arg(in, in, in, out) is cc_multi.
% deconstruct(Data, NonCanon, Functor, Arity, Arguments)
%
% Given a data item (Data), binds Functor to a string representation
% of the functor, Arity to the arity of this data item, and Arguments
% to a list of arguments of the functor. The arguments in the list
% are each of type univ.
%
% The cost of calling deconstruct depends greatly on how many arguments
% Data has. If Data is an array, then each element of the array is
% considered one of its arguments. Therefore calling deconstruct
% on large arrays can take a very large amount of memory and a very
% long time. If you call deconstruct in a situation in which you may
% pass it a large array, you should probably use limited_deconstruct
% instead.
%
:- 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.
% deconstruct_du(Data, NonCanon, FunctorNumber, Arity, Arguments)
%
% Given a data item (Data) which has a discriminated union type, binds
% FunctorNumber to the number of the functor in lexicographic order,
% Arity to the arity of this data item, and Arguments to a list of
% arguments of the functor. The arguments in the list are each of type
% univ.
%
% Fails if Data does not have discriminated union type.
%
:- pred deconstruct_du(T, noncanon_handling, functor_number_lex,
int, list(univ)).
:- mode deconstruct_du(in, in(do_not_allow), out, out, out) is semidet.
:- mode deconstruct_du(in, in(include_details_cc), out, out, out) is cc_nondet.
:- mode deconstruct_du(in, in, out, out, out) is cc_nondet.
% limited_deconstruct(Data, NonCanon, MaxArity,
% Functor, Arity, Arguments)
%
% limited_deconstruct works like deconstruct, but if the arity of T is
% greater than MaxArity, limited_deconstruct fails. This is useful in
% avoiding bad performance in cases where Data may be a large array.
%
% Note that this predicate only returns an answer when NonCanon is
% do_not_allow or canonicalize. If you need the include_details_cc
% behaviour use deconstruct.limited_deconstruct_cc/3.
%
:- pred limited_deconstruct(T, noncanon_handling, int, string, int,
list(univ)).
:- mode limited_deconstruct(in, in(do_not_allow), in, out, out, out)
is semidet.
:- mode limited_deconstruct(in, in(canonicalize), in, out, out, out)
is semidet.
:- pred limited_deconstruct_cc(T::in, int::in,
maybe({string, int, list(univ)})::out) is cc_multi.
%--------------------------------------------------%
%--------------------------------------------------%