
read_annotated(+Stream, -Term, -AnnTerm)

   Read term with type and source position information

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

Type
   Term I/O

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 --- Stream is not instantiated.
     5 --- Stream is not an atom or a stream handle.
   190 --- End of file was encountered before reading any character.
   192 --- Stream is not an input stream.
   193 --- Stream is an illegal stream specification.
   198 --- 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
