Version 1.1 of ai12s/ai12-0384-1.txt
!standard 4.10(0) 20-06-10 AI12-0384-1/01
!class Amendment 20-06-10
!status work item 20-06-10
!status received 20-06-10
!priority Low
!difficulty Medium
!subject Fixups for Put_Image and Text_Buffers
!summary
Add operations to associate with a Text_Buffer an adjustable level of
indentation, and a character position within the line. Eliminate the
End_Of_Line function. Add functions for putting and getting the content
of the Text_Buffer as a UTF_8 String or as a UTF_16 Wide_String. Provide
a New_Line string rather than a New_Line_Count. Add parameters to Get
and Wide_Get to control what to substitute for characters that cannot be
directly represented in Character and Wide_Character, respectively.
Provide functions Get and Wide_Get for retrieving the whole buffer
with possibly multiple-character substitutions for unrepresentable
characters using a user-defined substitution function.
Allow Put_Image on an Unchecked Union. Give implementors a bit
more flexibility about whether to support Put_Image on types
on which Text_Buffers themselves depend. Clarify
that T'Put_Image on a private type breaks privacy, and displays
the same thing that the full type would display.
!problem
As part of implementing the Put_Image attribute (AI12-0020-1) and the
Text_Buffers package (AI12-0340-1), a certain number of issues were
identified with the proposed features. In particular:
(1) Defining the Put_Image for a composite type is likely to result in
multiple lines of output. It seems highly desirable that such output is
reasonably indented, to reflect the nesting of components and
subcomponents. As currently defined the Put_Image attribute takes only
the Text_Buffer and the value whose image is to be produced. If we want
to provide some level of indenting, we need to incorporate into the
Text_Buffer some notion of a current level of indentation.
(2) Any attempt to break lines of output at some reasonable length
relies on knowing the position within the current line. As characters
are added to a Text_Buffer it is straightforward for the buffer to keep
track of how many characters have been added to it since the most recent
newline. It is hard to do it in other ways, since, as mentioned above,
Put_Image routines are called with only a Text_Buffer and a value as a
parameter. For example, it might be reasonable to display a short array
all on the current line, unless we are already far to the right, in
which case one might want to put the array on its own line, or break the
array across multiple lines. This is hard to decide without knowing
where on the current line of output the Put_Image is invoked.
(3) The Get and Wide_Get routines currently produce
implementation-defined results when the characters are not representable
directly as Character or Wide_Character, respectively. The actual
substitution performed would be better if it were user defined, and
could support the reversibility of 'Image/'Value for enumeration types
that have enumeration literals whose characters are not all
representable with Characters or Wide_Characters. It would also be
useful if UTF_8 and UTF_16 could be used for filling and emptying
Text_Buffers, since we anticipate that many implementations will use
UTF_8 or UTF_16 internally for representing identifiers in their symbol
tables, and perhaps also for the characters in a Text_Buffer. This can
also make the process "loss-less" while permitting efficient internal
representation.
(4) Providing a "peek-ahead" capability via End_Of_Line for a newline
character sequence is not particularly useful unless characters are
being removed from the buffer one character at a time. And even then,
other "peek-ahead" would also be needed (e.g. for white space, commas,
brackets, etc.) to do any sort of complex parsing as might be required
by a general 'Value implementation. We therefore remove the End_Of_Line
function, provide a New_Line_String instead of the New_Line_Count, and
leave for future standardization sufficient peek-ahead functions to
support 'Value or similar lexing and parsing uses of Text_Buffers.
(5) An AARM note says that Put_Image on an Unchecked_Union will raise
Program_Error. It might be nice if some other behavior were permitted.
!proposal
(1) We propose to add indentation to the root interface, because it is
not easy to add indentation in an extension, given that the various
Put_Image routines are only passed Root_Buffer_Type'Class. We propose a
Current_Indent function, and Increase/Decrease_Indent procedures, as
primitives, which determine how many spaces are inserted at the
beginning of the buffer, and at the beginning of each nonempty line.
(2) We propose to add a Position_In_Line function that indicates which
character position of the line is the next to be written, so a Put_Image
routine can decide whether and when to split its output into multiple
lines.
(3) We add a Substitute parameter of a single Character or Wide_Character to
the Get and Wide_Get procedures, respectively, analogous to the
Substitute parameter in Ada.Characters.Conversions.To_String. We add
Get and Wide_Get functions that take a Substitute parameter that is of
an access-to-function type, which replaces an unrepresentable character
with a string of representable characters. We add Get/Put_UTF_8 and
Wide_Get/Put_UTF_16 operations. We provide implementation-defined
Substitute and Wide_Substitute functions that perform the substitution
expected by the 'Value and 'Wide_Value functions for enumeration
types with literals that are not directly representable using
Character or Wide_Character.
(5) We give an implementation permission for the default Put_Image for
an unchecked union to produce a recognizable string rather than raise
Program_Error.
!wording
Modify 4.10 (7/5):
where the Wide_Wide_String value written out to the [stream]{text
buffer} is defined as follows:
Add after 4.10 (23/5):
For a private type or a private extension T, the default
implementation of T'Put_Image is the same as that for its full type.
Modify 4.10 (28/5):
S'Wide_Image calls S'Put_Image passing Arg (which will typically store
a sequence of character values in a text buffer) and then returns the
result of retrieving the contents of that buffer with {function}
Wide_Get {with Substitute being Wide_Image_Substitution}. The lower
bound of the result is one.
Modify 4.10 (31/5):
S'Image calls S'Put_Image passing Arg (which will typically store a
sequence of character values in a text buffer) and then returns the
result of retrieving the contents of that buffer with {function} Get
{with Substitute being Image_Substitution}. The lower bound of the
result is one.
Add after 4.10 (40/5):
* For a string type, implementations may produce an image corresponding
to a string literal.
* For an unchecked union type, implementations may
raise Program_Error or produce some recognizable
image (such as "(UNCHECKED UNION)").
Modify A.4.12 (2/5):
{with Ada.Strings.UTF_Encoding.Wide_Wide_Strings;}
package Ada.Strings.Text_Buffers
with Pure, Nonblocking, Global => null is
Add after A.4.12(4/5):
subtype Positive_Text_Buffer_Count is
Text_Buffer_Count range 1 .. Text_Buffer_Count'Last;
New_Line_String : constant String := /implementation-defined/;
Modify A.4.12(5/5):
New_Line_Count : constant Positive_Text_Buffer_Count :=
[/implementation-defined/]{New_Line_String'Length};
Delete A.4.12(6/5):
type Root_Buffer_Type is abstract tagged private;
and replace with:
type Root_Buffer_Type is abstract tagged limited private
{with Default_Initial_Condition =>
Character_Count (Root_Buffer_Type) = 0
and then Current_Indent (Root_Buffer_Type) = 0
and then Position_In_Line (Root_Buffer_Type) = 1;
Modify A.4.12 (9/5):
procedure Get (
Buffer : in out Root_Buffer_Type;
Item : out String;
Last : out Natural{;
Substitute : in Character := ' '}) is abstract
with Post'Class =>
(declare
Num_Read : constant Text_Buffer_Count :=
Text_Buffer_Count'Min
(Character_Count(Buffer)'Old, Item'Length);
begin
Last = Num_Read + Item'First - 1 and then
Character_Count (Buffer) =
Character_Count (Buffer)'Old - Num_Read);
Modify A.4.12 (10/5):
procedure Wide_Get (
Buffer : in out Root_Buffer_Type;
Item : out Wide_String;
Last : out Natural{;
Substitute : in Wide_Character := ' '}) is abstract
with Post'Class =>
(declare
Num_Read : constant Text_Buffer_Count :=
Text_Buffer_Count'Min
(Character_Count(Buffer)'Old, Item'Length);
begin
Last = Num_Read + Item'First - 1 and then
Character_Count (Buffer) =
Character_Count (Buffer)'Old - Num_Read);
Delete the End_Of_Line function at A.4.12 (12/5).
Modify A.4.12 (13/5, 14/5, 15/5) to replace Post'Class in each with:
with Post'Class =>
Character_Count (Buffer) =
Character_Count (Buffer)'Old + Item'Length +
(if Position_In_Line (Buffer)'Old = 1
then Current_Indent (Buffer) else 0);
Add after A.4.12 (16/5):
procedure Put_UTF_8 (
Buffer : in out Root_Buffer_Type;
Item : in UTF_Encoding.UTF_8_String) is abstract
with Post'Class =>
Character_Count (Buffer) =
Character_Count (Buffer)'Old +
UTF_Encoding.Wide_Wide_Strings.Decode (Item)'Length +
(if Position_In_Line (Buffer)'Old = 1
then Current_Indent (Buffer) else 0);
procedure Wide_Put_UTF_16 (
Buffer : in out Root_Buffer_Type;
Item : in UTF_Encoding.UTF_16_Wide_String) is abstract
with Post'Class =>
Character_Count (Buffer) =
Character_Count (Buffer)'Old +
UTF_Encoding.Wide_Wide_Strings.Decode (Item)'Length +
(if Position_In_Line (Buffer)'Old = 1
then Current_Indent (Buffer) else 0);
function Get_UTF_8 (
Buffer : in out Root_Buffer_Type)
return UTF_Encoding.UTF_8_String
with Post'Class => Character_Count (Buffer) = 0;
function Wide_Get_UTF_16 (
Buffer : in out Root_Buffer_Type)
return UTF_Encoding.UTF_16_Wide_String
with Post'Class => Character_Count (Buffer) = 0;
type Substitution_Function is
access function (Item : Wide_Wide_Character) return String;
type Wide_Substitution_Function is
access function (Item : Wide_Wide_Character) return Wide_String;
function Image_Substitution
(Item : Wide_Wide_Character) return String;
function Wide_Image_Substitution
(Item : Wide_Wide_Character) return Wide_String;
function Get (
Buffer : in out Root_Buffer_Type;
Substitute : in Substitution_Function := Image_Substitution)
return String
with Post'Class =>
Get'Result'First = 1 and then Character_Count (Buffer) = 0;
function Wide_Get (
Buffer : in out Root_Buffer_Type
Substitute : in Wide_Substitution_Function := Wide_Image_Substitution)
return Wide_String
with Post'Class =>
Wide_Get'Result'First = 1 and then Character_Count (Buffer) = 0;
function Position_In_Line
(Buffer : Root_Buffer_Type) return Positive_Text_Buffer_Count;
Standard_Indent : constant Positive_Text_Buffer_Count := 3;
function Current_Indent
(Buffer : Root_Buffer_Type) return Text_Buffer_Count;
procedure Increase_Indent
(Buffer : in out Root_Buffer_Type;
Amount : in Text_Buffer_Count := Standard_Indent)
with Post'Class =>
Current_Indent (Buffer) = Current_Indent (Buffer)'Old + Amount;
procedure Decrease_Indent
(Buffer : in out Root_Buffer_Type;
Amount : in Text_Buffer_Count := Standard_Indent)
with Pre'Class =>
Current_Indent (Buffer) >= Amount
or else raise Constraint_Error,
Post'Class =>
Current_Indent (Buffer) =
Current_Indent (Buffer)'Old - Amount
Modify A.4.12 (19/5):
type Buffer_Type is new Root_Buffer_Type with private
[with Default_Initial_Condition =>
Character_Count (Buffer_Type) = 0];
Delete A.4.12 (20/5) because the type is a nonabstract private extension
so there is no need to visibly override the inherited operations; they
can be overridden in the private part.
Modify A.4.12 (23/5) with:
type Buffer_Type (Max_Characters : Text_Buffer_Count)
is new Root_Buffer_Type with private
[with Default_Initial_Condition =>
Character_Count (Buffer_Type) = 0];
Replace A.4.12 (24/5) with:
-- Overridings of Put, Wide_Put, and Wide_Wide_Put are declared here
-- with the aspect specification
-- with Pre =>
-- Character_Count (Buffer) + Item'Length +
-- (if Position_In_Line (Buffer)'Old = 1
-- then Current_Indent (Buffer) else 0) <= Buffer.Max_Characters
-- or else raise Constraint_Error
-- Overridings of Put_UTF_8 and Wide_Put_UTF_16 are declared here
-- with the aspect specification
-- with Pre =>
-- Character_Count (Buffer) +
-- UTF_Encoding.Wide_Wide_Strings.Decode (Item)'Length +
-- (if Position_In_Line (Buffer)'Old = 1
-- then Current_Indent (Buffer) else 0) <= Buffer.Max_Characters
-- or else raise Constraint_Error
Modify A.4.12 (27/5):
{New_Line_String is the representation for a new line in a
Text_Buffer.} New_Line stores [New_Line_Count characters that
represent a new line] {New_Line_String} into a text buffer.
[End_of_Line returns True if the next characters to be retrieved from
the text buffer represent a new line.] {Position_In_Line returns the
character position in the current line of output, starting with one.
Current_Indent returns the current indentation associated with the
buffer, with zero meaning there is no indentation in effect;
Increase_Indent and Decrease_Indent increase or decrease the
indentation associated with the buffer.}
Modify A.4.12 (28/5):
A call to Put{, Put_UTF_8}, Wide_Put{, Wide_Put_UTF_16}, or
Wide_Wide_Put stores a sequence of characters into the text buffer{,
preceded by Current_Indent(Buffer) spaces (Wide_Wide_Characters with
position 32) if they would have been the first characters on the
current line}.
Modify A.4.12 (29/5):
A call to Get{, Get_UTF_8}, Wide_Get{, Wide_Get_UTF_16}, or
Wide_Wide_Get returns the same sequence of characters as was present
in the calls that stored the characters into the buffer{, if
representable}. For a call to Get, if any character {C} in the
sequence is not defined in Character, [the result is implementation
defined] {C is replaced with the Substitute character when calling
procedure Get, and with Substitute (C) when calling the function Get}.
Similarly, for a call to Wide_Get, if any character {C} in the
sequence is not defined in Wide_Character, [the result is
implementation defined] {C is replaced with the Substitute character
when calling procedure Wide_Get, and with Subsititute (C) when calling
the function Wide_Get.
The functions Image_Substitution and Wide_Image_Substitution perform
the implementation-defined substitutions necessary to support the
Value and Wide_Value attributes for enumeration types that have
literals using a character that is not representable directly as
Character or Wide_Character, respectively}.
!discussion
See !problem and !proposal
We have clarified that private types have the same default
implementation of Put_Image as their full type. Another choice would be
to say that Put_Image is not defined on a private type unless explicitly
provided, though that would clearly make composability more of a pain,
analogous to what happens with 'Write on limited types. Clearly any
implementor of a private type should specify Put_Image if they are
concerned about the loss of information hiding. For compatibility
reasons we can't really change what Put_Image does on the full type, and
making the run-time semantics of Put_Image depend on where you invoke it
seems like a generally bad idea. So I think we are stuck with either
hiding it completely, or having it do the same thing as on the full
type. Actually, one option is to hide 'Image, but not hide 'Put_Image,
on a private type. That would mean that composability is not interrupted,
but a "casual" use of 'Image would not be possible without an explicit
declaration of Put_Image in the visible part of the package.
!ASIS
No ASIS effect.
!ACATS test
An ACATS C-Test is needed to check the various subprograms and the image
attributes are implemented as expected.
that the new rules are enforced,
rather than the previous rules. The test program given below can be the
basis of an ACATS C-Test.
!appendix
****************************************************************
Questions? Ask the ACAA Technical Agent