[m-rev.] Improvements to pprint.m

Peter Ross peter.ross at miscrit.be
Thu Apr 26 20:59:58 AEST 2001


On Thu, Apr 26, 2001 at 03:42:29AM -0700, Ralph Becket wrote:
> Estimated hours taken: 2

You forgot the Branches line.  I would suggest that this is a useful
enough change that it be put on the release branch as well.

> 
> Improve the pretty printer's output for various types.  This makes
> the debugger's pretty format much more useful.
> 
> library/pprint.m:
> 	Extended the pretty printer's to_doc/2 function to format
> 	lists, tuples and maps more readably.  Lists now appear
> 	as [a, b, c, ...], tuples as {a, b, c}, and maps as
> 	map(key1 -> value1, key2 -> value2, ...).  Ellipsis
> 	represents the remainder of a list of map where the depth
> 	limit has been reached.
> 
> 
> 
> Index: pprint.m
> ===================================================================
> RCS file: /home/mercury1/repository/mercury/library/pprint.m,v
> retrieving revision 1.4
> diff -u -r1.4 pprint.m
> --- pprint.m	2000/05/25 13:14:02	1.4
> +++ pprint.m	2001/04/25 16:07:57
> @@ -291,7 +291,7 @@
>  
>  :- implementation.
>  
> -:- import_module std_util, char.
> +:- import_module std_util, char, array, map.
>  
>  :- type doc
>      --->    'NIL'
> @@ -381,7 +381,7 @@
>          be(W, K, [I - X | Z])
>      ).
>  
> -%
> ------------------------------------------------------------------------
> ---- %
> +%----------------------------------------------------------------------
> --------%
>  
>      % Decide whether flattening a given doc will allow it and
>      % up to the next possible 'LINE' in the following docs to
> @@ -398,7 +398,7 @@
>      fits_flattened([DocToFlatten], RemainingWidth, RemainingWidth0),
>      fits_on_rest(FollowingDocs, RemainingWidth0).
>  
> -%
> ------------------------------------------------------------------------
> ---- %
> +%----------------------------------------------------------------------
> --------%
>  
>      % Decide if a flattened list of docs will fit on the remainder
>      % of the line.  Computes the space left over if so.
> @@ -418,7 +418,7 @@
>      R0 > L,
>      fits_flattened(Z, R0 - L, R).
>  
> -%
> ------------------------------------------------------------------------
> ---- %
> +%----------------------------------------------------------------------
> --------%
>  
>      % Decide if a list of indent-doc pairs, up to the first 'LINE',
>      % will fit on the remainder of the line.
> @@ -472,10 +472,8 @@
>  separated(_,  _,   []) = nil.
>  
>  separated(PP, Sep, [X | Xs]) =
> -    ( if Xs = [] then
> -        PP(X)
> -      else
> -        PP(X) `<>` (Sep `<>` separated(PP, Sep, Xs))
> +    ( if Xs = [] then PP(X)
> +                 else PP(X) `<>` (Sep `<>` separated(PP, Sep, Xs))
>      ).
>  

I don't believe that this allowed by our coding convention, even if it
does read quite nicely.

>  
> %-----------------------------------------------------------------------
> -------%
> @@ -506,7 +504,15 @@
>  
>  to_doc(Depth, X) = Doc :-
>      deconstruct(X, Name, Arity, UnivArgs),
> -    ( if Arity = 0 then
> +    (      if dynamic_cast_to_list(X, List) then
> +        Doc = list_to_doc(Depth, List)
> +      else if dynamic_cast_to_array(X, Array) then
> +        Doc = array_to_doc(Depth, Array)
> +      else if dynamic_cast_to_tuple(X, Tuple) then
> +        Doc = tuple_to_doc(Depth, Tuple)
> +      else if dynamic_cast_to_map(X, Map) then
> +        Doc = map_to_doc(Depth, Map)
> +      else if Arity = 0 then
>          Doc = text(Name)
>        else if Depth =< 0 then
>          Doc = text(Name) `<>` text("/") `<>` poly(i(Arity))
> @@ -526,6 +532,154 @@
>      ).
>  
>  %
> ------------------------------------------------------------------------
> ---- %
> +
> +:- some [T2] pred dynamic_cast_to_array(T1, array(T2)).
> +:-           mode dynamic_cast_to_array(in, out) is semidet.
> +
> +dynamic_cast_to_array(X, A) :-
> +
> +        % If X is an array then it has a type with one type argument.
> +        %
> +    [ArgTypeDesc] = type_args(type_of(X)),
> +
> +        % Convert ArgTypeDesc to a type variable ArgType.
> +        %
> +    (_ `with_type` ArgType) `has_type` ArgTypeDesc,
> +
> +        % Constrain the type of A to be array(ArgType) and do the
> +        % cast.
> +        %
> +    dynamic_cast(X, A `with_type` array(ArgType)).
> +
> +%----------------------------------------------------------------------
> --------%
> +
> +:- some [T2] pred dynamic_cast_to_list(T1, list(T2)).
> +:-           mode dynamic_cast_to_list(in, out) is semidet.
> +
> +dynamic_cast_to_list(X, L) :-
> +
> +        % If X is a list then it has a type with one type argument.
> +        %
> +    [ArgTypeDesc] = type_args(type_of(X)),
> +
> +        % Convert ArgTypeDesc to a type variable ArgType.
> +        %
> +    (_ `with_type` ArgType) `has_type` ArgTypeDesc,
> +
> +        % Constrain the type of L to be list(ArgType) and do the
> +        % cast.
> +        %
> +    dynamic_cast(X, L `with_type` list(ArgType)).
> +
> +%----------------------------------------------------------------------
> --------%
> +
> +:- some [T2, T3] pred dynamic_cast_to_map(T1, map(T2, T3)).
> +:-               mode dynamic_cast_to_map(in, out) is semidet.
> +
> +dynamic_cast_to_map(X, M) :-
> +
> +        % If X is a map then it has a type with two type arguments.
> +        %
> +    [KeyTypeDesc, ValueTypeDesc] = type_args(type_of(X)),
> +
> +        % Convert the TypeDescs to type variables.
> +        %
> +    (_ `with_type` KeyType) `has_type` KeyTypeDesc,
> +    (_ `with_type` ValueType) `has_type` ValueTypeDesc,
> +

This construction looks like something that should be added to the std
library.

> +        % Constrain the type of M to be map(KeyType, ValueType)
> +        % and do the cast.
> +        %
> +    dynamic_cast(X, M `with_type` map(KeyType, ValueType)).
> +
> +%----------------------------------------------------------------------
> --------%
> +
> +:- pred dynamic_cast_to_tuple(T, T).
> +:- mode dynamic_cast_to_tuple(in, out) is semidet.
> +
> +dynamic_cast_to_tuple(X, X) :-
> +
> +        % If X is a tuple then it's functor name is {}.
> +        %
> +    functor(X, "{}", _Arity).
> +
> +%----------------------------------------------------------------------
> --------%
> +
> +    % XXX Ideally we'd just walk the array.  But that's an optimization
> +    % for another day.
> +    %
> +:- func array_to_doc(int, array(T)) = doc.
> +
> +array_to_doc(Depth, A) =
> +    text("array") `<>` parentheses(list_to_doc(Depth,
> array__to_list(A))).
> +
> +%----------------------------------------------------------------------
> --------%
> +
> +:- func list_to_doc(int, list(T)) = doc.
> +
> +list_to_doc(Depth, Xs) =
> +    brackets(separated_to_depth(to_doc, group(comma_space_line), Depth,
> Xs)).
> +
> +%----------------------------------------------------------------------
> --------%
> +
> +:- func map_to_doc(int, map(T1, T2)) = doc.
> +
> +map_to_doc(Depth, X) =
> +    text("map") `<>` parentheses(
> +        group(
> +            nest(2, 
> +                line `<>`
> +                separated_to_depth(map_pair_to_doc, comma_space_line,
> Depth,
> +                    map__to_assoc_list(X)
> +                )
> +            )
> +        )
> +    ).
> +
> +
> +
> +:- func map_pair_to_doc(int, pair(T1, T2)) = doc.
> +
> +map_pair_to_doc(Depth, Key - Value) =
> +    to_doc(Depth - 1, Key) `<>` text(" -> ") `<>`
> +        nest(2, group(line `<>` to_doc(Depth - 1, Value))).
> +
> +%----------------------------------------------------------------------
> --------%
> +
> +    % This should only really be used if the item in question really
> +    % is a tuple.
> +    %
> +:- func tuple_to_doc(int, T) = doc.
> +
> +tuple_to_doc(Depth, Tuple) = Doc :-
> +    deconstruct(Tuple, _Name, _Arity, UnivArgs),
> +    Args = list__map(
> +        ( func(UnivArg) = to_doc(Depth - 1, univ_value(UnivArg)) ),
> +        UnivArgs
> +    ),
> +    Doc = braces(separated(id, group(comma_space_line), Args)).
> +
> +%----------------------------------------------------------------------
> --------%
> +
> +    % This is pretty much the same as separated/3 except that it
> +    % takes a depth parameter (q.v. to_doc/2) and replaces the
> +    % tail of the list below the depth limit with ellipsis.
> +    %
> +:- func separated_to_depth(func(int, T) = doc, doc, int, list(T)) =
> doc.
> +
> +separated_to_depth(_,  _,   _,     []) = nil.
> +
> +separated_to_depth(PP, Sep, Depth, [X | Xs]) = Doc :-
> +    ( if Depth =< 0 then
> +        Doc = text("...")
> +      else if Xs = [] then
> +        Doc = PP(Depth, X)
> +      else
> +        Doc = PP(Depth, X) `<>`
> +              (Sep `<>` separated_to_depth(PP, Sep, Depth - 1, Xs))
> +    ).
> +
> +%----------------------------------------------------------------------
> --------%
>  
>  word_wrapped(String) =
>      separated(
> --------------------------------------------------------------------------
> mercury-reviews mailing list
> post:  mercury-reviews at cs.mu.oz.au
> administrative address: owner-mercury-reviews at cs.mu.oz.au
> unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
> subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
> --------------------------------------------------------------------------
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list