[ Term I/O | Reference Manual | Alphabetic Index ]

# read_annotated(+Stream, -Term, -AnnTerm)

Read term with type and source position information

Stream
  Stream handle or alias (atom)
Term
  Variable or term
AnnTerm
  Variable or term

## Description

Reads the next input term (up to the end of file, or up to a fullstop) from from the input stream Stream, and returns this term as Term, and a descriptor AnnTerm. AnnTerm is structurally similar to Term and contains all information about the term, plus additional type information, variable names, and source position annotations for all subterms.

The structure of the descriptive terms is as follows:

            :- export struct(annotated_term(
                    term,                   % var, atomic or compound
                    type,                   % term type (see below)
                    file,                   % source file name (atom)
                    line,                   % source line (integer)
                    from, to                % source position (integers)
                    ...
            )).

The type-field describes the type of the parsed term and is one of the following:

        integer
        float
        rational
        breal
        atom
        string
        compound            term is compound (with annotated subterms)
        anonymous           term is a variable (was anonymous (_) in source)
        var(NameAtom)       term is a variable (with the given source name)
        var                 term is a variable (introduced by macro expansion)
        end_of_file         end of file was read (term is end_of_file)

These type names correspond to the ones used in type_of/2, except that they convey additional information about variables and end_of_file..

In the case of atomic terms and variables, the term-field simply contains the plain parsed term. For compound terms, the term-field contains a structure whose functor is the functor of the plain term, but whose arguments are annotated versions of the plain term arguments.

E.g. the source term

            3

is parsed as

            annotated_term(3, integer, ...)

The source term

            foo(bar, X, _, 3)

is parsed as

            annotated_term(foo(
                annotated_term(bar, atom, ...),
                annotated_term(X, var('X'), ...),
                annotated_term(_, anonymous, ...),
                annotated_term(3, integer, ...)),
            compound, ...)

The source term

            [1,2]

is parsed as

            annotated_term(.(
                annotated_term(1, integer, ...),
                    annotated_term(.(
                            annotated_term(2, integer, ...),
                            annotated_term([], atom, ...)),
                        compound, ...)),
                compound, ...)

The file/line/from/to-fields of an annotated term describe the "source position" of the term. The fields contain:

file
  The canonical file name of the source file (an atom), or the empty atom '' if the source is not a file or not known.
line
  The line number in the source stream (positive integer).
from, to
  The exact term position as integer offsets in the source stream, starting at from and ending at to-1.

The source position of a whole (sub)term is defined as the source position of the unique token (sometimes token pair) which represents that (sub)term. The representing token (pair) is defined as follows:

- atoms, strings and unsigned numbers are represented by their corresponding IDENTIFIER, NUMBER or STRING token.
- signed numbers are represented by two consecutive tokens (sign+number)
- compound terms in canonical notation are represented by two consecutive tokens (functor and opening parenthesis)
- compound terms in operator syntax are represented by the operator's IDENTIFIER token
- lists:

  a proper list [a,b] has subterms

              [a,b]   represented by the [ token,
              [b]     represented by the , token,
              []      represented by the ] token,
              a       represented by itself,
              b       represented by itself.

  a general list [a,b|T] has subterms

              [a,b|T] represented by the [ token,
              [b|T]   represented by the , token,
              T       represented by itself,
              a       represented by itself,
              b       represented by itself.

  Note that the | and ] tokens do not represent any term.
- special notations:

  {X}

              '{}'(X) represented by the { token,
              X       represented by itself

  X[Args]

              subscript(X, [...]) represented by the [ token,
              X,Args  represented by themselves

  X{Args}

              'with attributes'(X,[Args]) represented by { token,
              X,Args  represented by themselves

  a{Args}

              with(a,[Args])  represented by the { token
              a,Args  represented by themselves

  X(Args)

              apply(X,[Args]) represented by the ( token
              X,Args  represented by themselves

Terms that were read from source may be subject to macro expansion (see macro/3, expand_macros/2). In that case, term components that were introduced by the expansion may not have an exactly corresponding item in the source (but will usually inherit a meaningful, though not necessarily unique, source position). Moreover, variables that were newly introduced by the expansion have a type-field of 'var' without name information. Also, 'anonymous' variables may have more than one occurrence after expansion.

If only end of file is read, the event 190 is raised. The default handler unifies Term with an annotated term of the form annotated_term{term:end_of_file,type:end_of_file}, and the source location is the last position in the file.

The default action for syntax errors is to print a warning and fail.

### Modes and Determinism

- read_annotated(+, -, -) is semidet

### Modules

This predicate is sensitive to its module context (tool predicate, see @/2).

### Fail Conditions

Fails if a syntax error was detected and no term could be read

### Exceptions

(4) instantiation fault
  Stream is not instantiated.
(5) type error
  Stream is not an atom or a stream handle.
(190) end of file reached
  End of file was encountered before reading any character.
(192) illegal stream mode
  Stream is not an input stream.
(193) illegal stream specification
  Stream is an illegal stream specification.
(198) reading past the file end
  Trying to read even after the error 190 was raised.

## Examples

    ?- read_annotated(input,T,AT).
     33.

    T = 33
    AT = annotated_term(33, integer, user, 1, 0, 2)
    Yes (0.00s cpu)

    ?- read_annotated(input,T,AT).
     foo(bar).

    T = foo(bar)
    AT = annotated_term(foo(
                annotated_term(bar, atom, user, 2, 8, 11)
            ), compound, user, 2, 4, 8)
    Yes (0.00s cpu)

    ?- read_annotated(input,X).
     a + 3.

    T = a + 3
    AT = annotated_term(
                annotated_term(a, atom, user, 3, 14, 15)
            +   annotated_term(3, integer, user, 3, 18, 19),
            compound, user, 3, 16, 17)
    Yes (0.00s cpu)

    ?- read_annotated(input,X).
     [a,b].

    T = [a, b]
    AT = annotated_term([
                annotated_term(a, atom, user, 4, 22, 23)|
                annotated_term([
                        annotated_term(b, atom, user, 4, 24, 25)|
                        annotated_term([], atom, user, 4, 25, 26)
                    ], compound, user, 4, 23, 24)
            ], compound, user, 4, 21, 22)
    Yes (0.00s cpu)

## See Also

read_annotated / 2, read / 1, read_term / 2, read_token / 2, read_token / 3, expand_macros / 2, macro / 3, type_of / 2