[m-rev.] Improvements to pprint.m

Ralph Becket rbeck at microsoft.com
Thu Apr 26 20:42:29 AEST 2001


Estimated hours taken: 2

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))
     ).
 
 
%-----------------------------------------------------------------------
-------%
@@ -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,
+
+        % 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
--------------------------------------------------------------------------



More information about the reviews mailing list