Next: , Previous: (dir), Up: (dir)

Introduction

Auto_Text_IO automates the generation of Put and Get subprograms for user-defined types. It reads a parent package spec, and writes child packages containing Get and Put subprograms for each type in the spec.

Auto_Text_IO can generate up to four files; a public child spec and body, and a private child spec and body. The private child contains Put and Get subprograms for types declared in the private part of the parent package.

See also auto_text_io.html.


Next: , Previous: Top, Up: Top

1 Naming Conventions

Auto_Text_IO uses a naming convention when picking names for child packages, and in general requires the user to also follow the naming convention for user-written packages.

These rules are encoded in the procedures Auto_Text_IO.Text_IO_Child_Name and Auto_Text_IO.Private_Text_IO_Child_Name. If you wish to use a different naming convention, you can rewrite those procedures.


Next: , Previous: Naming Conventions, Up: Naming Conventions

1.1 Parent Names

The only requirement on parent names is that generic package names must start with Gen_.


Next: , Previous: Parent Names, Up: Naming Conventions

1.2 Child Names

The public child package name is the parent package name with .Text_IO appended. In Ada 83 mode, _Text_IO is used instead.

The private child package name is the parent package name with .Private_Text_IO appended. Private children are not supported in Ada 83 mode.

For example, a parent package named Cards has text io children named Cards.Text_IO and Cards.Private_Text_IO.

If the parent package is generic, the child names have .Gen_Text_IO or .Gen_Private_Text_IO appended. Generic packages are not supported in Ada 83 mode.


Previous: Child Names, Up: Naming Conventions

1.3 Generic Formal Packages

When the parent package is generic, often it has generic formal package parameters. Then the text io child will also have generic formal package parameters, for the text_io children of the parent's generic formal package parameters.

To make the generic formal package parameter visible in the child, it must be renamed in the parent; the name must be the generic formal parameter name, with Parent_ prepended.

The name of the generic formal parameter in the child is then the generic formal parameter name in the parent, with _Text_IO appended.

When the parent package is itself a child of an ancestor generic package, the text_io child may require a generic formal package parameter for the ancestor text_io child. The name of this generic formal parameter is the ancestor package name, with the Gen_ prefix stripped off, and _Text_IO appended.

In general, generic formal package parameters may need instantiation arguments (see Math_Scalar_Text_IO in the example below). In the packages generated by Auto_Text_IO, these arguments are always previous generic formal package parameters, and they name text_io packages corresponding to any generic ancestors of the parent package, and to the arguments of the corresponding generic formal package parameters of the parent package.

In some cases, not all of these arguments are needed, for example if no types from the formal package are used. However, it is not possible for Auto_Text_IO to determine which packages are needed, without compiling all previously generated packages and querying them. That would cause the makefiles to become quite complex. So we need help from the user; the comment -- auto_text_io: ignore must be applied to each generic formal package parameter that does not need a text_io child. This allows Auto_Text_IO to generate all text_io children for a library in one pass.

A simple example:

     with Ada.Numerics.Generic_Elementary_Functions;
     generic
        --  auto_text_io: ignore
        with package Elementary is new Ada.Numerics.Generic_Elementary_Functions (Real_Type);
     package SAL.Gen_Math.Gen_Scalar is
     ...
     end SAL.Gen_Math.Gen_Scalar;
     
     with SAL.Gen_Math.Gen_Scalar;
     generic
        --  auto_text_io: ignore
        with package Elementary is new Ada.Numerics.Generic_Elementary_Functions (Real_Type);
        with package Math_Scalar is new SAL.Gen_Math.Gen_Scalar (Elementary);
     package SAL.Gen_Math.Gen_DOF_3 is
     ...
     end SAL.Gen_Math.Gen_DOF_3;
     
     with SAL.Gen_Math.Gen_Text_IO;
     generic
        with package Math_Text_IO is new SAL.Gen_Math.Gen_Text_IO;
     package SAL.Gen_Math.Gen_Scalar.Gen_Text_IO is
     ...
     end SAL.Gen_Math.Gen_Scalar.Gen_Text_IO;
     
     with SAL.Gen_Math.Gen_Scalar.Gen_Text_IO;
     with SAL.Gen_Math.Gen_Text_IO;
     generic
        with package Math_Text_IO is new SAL.Gen_Math.Gen_Text_IO;
        with package Math_Scalar_Text_IO is new Parent_Math_Scalar.Gen_Text_IO (Math_Text_IO);
     package SAL.Gen_Math.Gen_DOF_3.Gen_Text_IO is
     ...
     end Gen_Math.Gen_DOF_3.Gen_Text_IO;

Given the declaration of SAL.Gen_Math.Gen_DOF_3, the child SAL.Gen_Math.Gen_DOF_3.Gen_Text_IO has the following generic formal package parameters:

Math_Text_IO
For the ancestor Gen_Math.
Math_Scalar_Text_IO
For the generic formal parameter Math_Scalar in Gen_Math.Gen_DOF_3.

Math_Scalar takes an argument of Math_Text_IO because Gen_Math.Gen_Scalar has a generic ancestor Gen_Math. It does not take a parameter Elementary_Text_IO, because of the comment auto_text_io: ignore.

However, this does not provide enough control; in some cases, we need to ignore only the instantation parameters, not an entire package. Here is a more complex example:

     generic
        --  Auto_Text_IO : ignore
        with package Elementary  is new Ada.Numerics.Generic_Elementary_Functions (Real_Type);
        with package Math_Scalar is new SAL.Gen_Math.Gen_Scalar (Elementary);
        --  Auto_Text_IO : ignore
        with package Math_DOF_3  is new SAL.Gen_Math.Gen_DOF_3 (Elementary, Math_Scalar);
        --  Auto_Text_IO : ignore
        with package Math_DOF_6  is new SAL.Gen_Math.Gen_DOF_6 (Elementary, Math_Scalar, Math_DOF_3);
     package SAL.Gen_Math.Gen_Den_Hart is
     
     generic
        with package Math_Text_IO is new SAL.Gen_Math.Gen_Text_IO;
        with package Math_Scalar_Text_IO is new Parent_Math_Scalar.Gen_Text_IO (Math_Text_IO);
     package SAL.Gen_Math.Gen_Den_Hart.Gen_Text_IO is
     ...
     end SAL.Gen_Math.Gen_Den_Hart.Gen_Text_IO;
     
     generic
        --  Auto_Text_IO : ignore
        with package Elementary    is new Ada.Numerics.Generic_Elementary_Functions (Real_Type);
        with package Math_Scalar   is new SAL.Gen_Math.Gen_Scalar (Elementary);
        with package Math_DOF_3    is new SAL.Gen_Math.Gen_Dof_3 (Elementary, Math_Scalar);
        with package Math_DOF_6    is new SAL.Gen_Math.Gen_Dof_6 (Elementary, Math_Scalar, Math_DOF_3);
        with package Math_Den_Hart is new SAL.Gen_Math.Gen_Den_Hart
          (Elementary,
           Math_Scalar,
           --  Auto_Text_IO : ignore
           Math_DOF_3,
           --  Auto_Text_IO : ignore
           Math_DOF_6);
     
     package SAL.Gen_Math.Gen_Manipulator is
     ...
     end SAL.Gen_Math.Gen_Manipulator;
     
     generic
        with package Math_Text_IO is new SAL.Gen_Math.Gen_Text_IO;
        with package Math_Scalar_Text_IO is new Parent_Math_Scalar.Gen_Text_IO (Math_Text_IO);
        with package Math_DOF_3_Text_IO is new Parent_Math_DOF_3.Gen_Text_IO (Math_Text_IO, Math_Scalar_Text_IO);
        with package Math_DOF_6_Text_IO is new Parent_Math_DOF_6.Gen_Text_IO (Math_Text_IO, Math_Scalar_Text_IO, Math_DOF_3_Text_IO);
        with package Math_Den_Hart_Text_IO is new Parent_Math_Den_Hart.Gen_Text_IO (Math_Text_IO, Math_Scalar_Text_IO);
     package SAL.Gen_Math.Gen_Manipulator.Gen_Text_IO is
     ...
     end SAL.Gen_Math.Gen_Manipulator.Gen_Text_IO;

The package SAL.Gen_Math.Gen_Den_Hart takes generic parameters Gen_DOF_3 and Gen_DOF_6, but does not need their text_io children. However, the package Gen_Manipulator does need their text_io children. So we must ignore only the instantiation parameters in Gen_Manipulator.Math_Den_Hart.


Next: , Previous: Naming Conventions, Up: Top

2 User overrides

For some types, the user may wish to provide their own body for the basic Put and Get subprograms, to enforce some restriction on the type or change the text format. For example, SAL.Gen_Math.Gen_Scalar.Trig_Pair_Type is output as a single float value in radians, rather than as a float pair. SAL.Gen_Math.Gen_Scalar.Limit_Type does input validation in Get.

This is handled by labeling the type with the comment -- Auto_Text_IO : separate, and providing a separate subprogram for the basic Put and Get. This is currently supported only for non-tagged record types. The specifications for the separate subprograms for a type named Foo_Type are:

        procedure Put_Foo
           (File                        : in Ada.Text_IO.File_Type;
            Item                        : in Foo_Type;
            Single_Line_Record          : in Boolean := False;
            Named_Association_Record    : in Boolean := False;
            Single_Line_Component       : in Boolean := True;
            Named_Association_Component : in Boolean := False)
           is separate;
     
        procedure Get_Foo
           (File                        : in     Ada.Text_IO.File_Type;
            Item                        :    out Foo_Type;
            Named_Association_Record    : in     Boolean := False;
            Named_Association_Component : in     Boolean := False)
           is separate;

One way to write the separate subprograms is to first let Auto_Text_IO write the normal subprograms, copy them to separate subprograms, edit them, and then apply the comment to the type.


Next: , Previous: User overrides, Up: Top

3 Adding a Standard type

Auto_Text_IO does not currently support all the types defined in Standard. Here is a description of how to add support for a new type; we use the fictitious type Foo as an example.


Previous: Adding a Standard type, Up: Top

4 Design considerations

Auto_Text_IO generates code that uses packages from Stephe's Ada Library at run-time.

One of those packages (SAL.Text_IO_Utils) provides simple whitepsace skipping, and one-character look-ahead. The one-character look-ahead is provided by Ada 96 Text_IO. The functionality provided by the Get routines generated by Auto_Text_IO is limited by this one-character lookahead. For example, it is not possible to determine by looking at the input whether named association is being used; that would require looking ahead past an identifier for “=>”. Similarly, it is not possible to support Ada comments in the input to Get; that would require two character lookahead.

An alternate design would be to use a lexer (such as provided by OpenToken) that allows looking ahead more characters. However, a lexer requires an internal input buffer. Thus Get operations generated by Auto_Text_IO could not be mixed with plain Ada.Text_IO Get operations; the Ada.Text_IO would not use the lexer's internal buffer, and would miss input.

It would be possible to provide a replacement for all of Ada.Text_IO, that used the lexer's internal input buffer. An early version of SAL provided such a package for Ada 83 (Ada 83 Text_IO did not provide any look-ahead), to support Ada comments in input files for unit tests. But at the moment, I've decided that's not worth it, partly because I now use AUnit for unit tests, and therefore have far less need for input files.