# Copyright 2022 Jeffrey Kegler
# This file is part of Marpa::R2.  Marpa::R2 is free software: you can
# redistribute it and/or modify it under the terms of the GNU Lesser
# General Public License as published by the Free Software Foundation,
# either version 3 of the License, or (at your option) any later version.
#
# Marpa::R2 is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser
# General Public License along with Marpa::R2.  If not, see
# http://www.gnu.org/licenses/.

=head1 NAME

Marpa::R2::Advanced::Thin - Direct access to Libmarpa

=head1 About this document

Most Marpa users can ignore this document.
It describes Marpa's "thin" interface,
which
provides efficient access to Marpa's core
library, Libmarpa.

The "thin" interface is very low-level and
is not designed to be convenient to use.
User-friendliness is expected to be provided by
an upper layer.
The "thin" interface
is intended for use in writing
those upper layers.
Libmarpa is also intended for writing applications,
when the programmer wants
to eliminate the overhead of an upper layer,
or wants the flexibility provided by direct access to Libmarpa,
and is willing to go to some extra effort.

=head1 How this document is written

This document assumes that the reader is familiar with
the other Marpa::R2 documentation.
and very familiar wth the Libmarpa API document.
Must of the terminology in this document is adopted
from the Libmarpa API document.
The reader will also have to know some C language --
at least enough to understand a discussion
written in terms of C functions,
their parameters and return values,
and C language macros.

This document
avoids
duplicating the material in the Libmarpa
API document.
Most Marpa thin interface functions correspond
directly to a Libmarpa method,
and their implementation follows a "general pattern".
This document describes that "general pattern".

Methods that follow
the general pattern are usually
not mentioned specifically.
Methods that are
exceptions
to the general pattern
are always mentioned,
and behaviors which deviate from the general
pattern are always described in detail.
This document also identifies
those Libmarpa
methods to which
no Marpa thin interface method directly corresponds.

This style of documentation 
is very efficient,
which is one reason that it is the
standard for C library interfaces to Perl.
Admittedly, however,
it is also very terse.
As an aid to
the reader,
an example of a script using
the Marpa thin interface is presented
L<below|"Example">.
While small, the example is non-trival.
It is also full,
in the sense it contains a complete
logic flow, starting with the definition
of the grammar
and continuing all the way to the iteration of
the values of an ambiguous parse.

=head1 Methods in the thin interface

While the thin interface has a few
methods of its own,
most of its methods are wrappers for a method
from the Libmarpa interface.
On the other hand,
many 
Libmarpa methods do not have
Marpa thin interface wrappers.
No internal Libmarpa method is part of the Marpa thin interface.

Additionally,
many of the
external Libmarpa methods are omitted because their function is performed
by the Marpa thin interface.
No thin interface method corresponds to
the C<marpa_check_version()> static method,
because the Marpa thin interface
interface handles its own version matching.

No thin interface method corresponds to any
of the Libmarpa configuration class methods.
No Marpa thin interface object corresponds
to Libmarpa's configuration objects.
Configuration in the Marpa thin
interface is done using Perl variables.

No Marpa thin interface method corresponds to the
C<marpa_g_ref()> and C<marpa_g_unref()> methods
because the thin interface handles the
reference counting of the Libmarpa objects it creates.
The application can rely on Libmarpa
objects being cleaned up properly as part of Perl's
usual garbage collection.
For the same reason,
no Marpa thin interface method corresponds to the
"ref" and "unref" methods of the other Libmarpa time
classes.

Whenever an external Libmarpa method is not mentioned
in this document, the reader can assume that
it has a wrapper that is implemented according
to the general pattern, as
described L<below|"The general pattern">.
Where the implementation of an
external Libmarpa method
is an exception to the general pattern,
its implementation will be explicitly described
and any corresponding Marpa thin interface method
will have a section devoted to it
and specifying its differences
from the general pattern.

=head1 Libmarpa time objects and constructors

As a reminder,
Libmarpa's major classes are,
in sequence,
configuration,
grammar, recognizer, bocage,
ordering, tree and value.
The one-letter abbreviations for these
are, respectively,
C<c>, C<g>, C<r>, C<b>, C<o>, C<t> and C<v>.

=for Marpa::R2::Display
ignore: 1

    Marpa_Config        Marpa::R2::Thin::C
    Marpa_Grammar       Marpa::R2::Thin::G
    Marpa_Recognizer    Marpa::R2::Thin::R
    Marpa_Bocage        Marpa::R2::Thin::B
    Marpa_Ordering      Marpa::R2::Thin::O
    Marpa_Tree          Marpa::R2::Thin::T
    Marpa_Value         Marpa::R2::Thin::V

=for Marpa::R2::Display::End

The thin interface implements a Perl class
corresponding to
each of Libmarpa time classes.
The thin interface does not implement a Perl class
corresponding to Libmarpa's configuration class.

Objects in the thin Marpa classes
should be treated as opaque scalars.
Applications must not define new methods,
constants or variables in a
thin Marpa classes.
Similarly, applications
must not
redefine, overload or remove existing elements.
Thin Marpa classes must not be subclassed.
Applications should restrict their operation on
objects in the Marpa thin classes to assignments;
calling methods of the class; and,
in those cases where
this document states that it is appropriate,
passing them as arguments.

Constructors for the time objects may be called using
the C<new> method of the corresponding Perl class.
For example,

=for Marpa::R2::Display
name: Thin example
partial: 1
normalize-whitespace: 1

    my $recce = Marpa::R2::Thin::R->new($grammar);

=for Marpa::R2::Display::End

Perl applications can destroy objects of the
Marpa thin classes 
by undefining them,
or by letting them go out of scope.
Application programmers do not need
to concern themselves
with the reference counting of Libmarpa objects.
The Marpa thin interface handles this.

=head1 The throw setting

One of the most important functions of
the Marpa thin interface
is to adapt Libmarpa's
error reporting to Perl.
Perl allows two kinds of error reporting.
Perl methods can communicate failure via their return values,
or they can throw exceptions.

Each has its place.
Throwing failure as an exception is the default in 
the Marpa thin interface because it is safer,
and because
it is convenient for prototyping and the first
cuts at a new application.
On the other hand, for Marpa thin
applications to have access
to the full flexibility and power of Libmarpa,
they must be able to set the Marpa thin
interface to return failure, instead of
throwing failure as an exception.

In choosing whether or not to throw a failure
as an exception,
almost every Marpa thin method obeys the throw
setting.
If the throw setting is 1, failure is thrown.
If the throw setting is 0, failure is returned.

The throw setting is 1 in newly created grammar
objects.
Once created, the throw setting of a grammar object
can be changed using the L<< C<throw_set()>
method|C<< $g->throw_set() >> >>
The throw setting of other objects is that
of their base grammar.

Nearly every Marpa thin method always obeys the throw setting.
Only three methods never obey the throw setting.
They are exceptions because their logic
controls the throw setting, so that a problem with them
suggests the throw setting itself may not be correct.
The methods which never obey the throw setting,
are
L<< C<< Marpa::R2::Thin::G->new() >>|C<< Marpa::R2::Thin::G->new() >> >>,
L<< C<throw_set()>|C<< $g->throw_set() >> >>
and L<< C<ruby_slippers_set()>|C<< $r->ruby_slippers_set() >> >>.
These methods throw all failures.

One method allows the throw setting to be overriden.
For convenience in using the Ruby Slippers technique,
the behavior of the L<< C<alternative()>
method|C<< $r->alternative() >> >>
is also affected by a separate "Ruby Slippers" flag.
For details, see
L<< the description of that
method|C<< $r->alternative() >> >>.

=head1 Error codes, names and descriptions

Errors in the Marpa thin interface come from
two sources:
Libmarpa, and the Marpa thin interface itself.
These will be called Libmarpa errors
and thin interface errors, respectively.

Internally, Marpa maintains two variables to
track recent errors.
These are the error code and the error description.
For every defined error code,
there is an error name.
Together, the error code, the error name
and the error descriptions are called the
"error variables".

When the most recent error was a Libmarpa error,
the error code is the Libmarpa error code, as described
in the Libmarpa API document.
A Libmarpa error code is a non-negative integer.
When the most recent error was a thin interface
error, the error code is
a Perl C<undef>.

Libmarpa's integral error codes are rarely used directly,
either in C or in Perl.
In C, the error codes are referred to using macros.
The macro names are available through the thin interface
as error names.
For details see L<the section on error methods|"Error methods">.
Thin interface errors do not have error names.

In addition to error names, there are error descriptions.

=over 4

=item *

Error names are short mnemonics.
Error descriptions are typically longer.

=item *

Error names and error codes have a one to one correspondence (bijection).
For a given error code, the error name will always
be the same, and vice versa.
Error descriptions 
may contain text relating, not just to the error code,
but to the specific error instance.

=item *

The error name is defined if and
only if
the error code is defined.
Error descriptions always exist,
whether or not there is an error code defined.

=item *

A thin interface error
will always have an error description.
A thin interface error
will never have an error name.

=item *

The programmer may expect error codes and error names
to remain stable and may write code that relies
on the numeric value of the error codes
and the text of the error name.
Applications should treat the text of an error description
as suitable for the purpose of passing it on to a human user,
and should otherwise regard it as opaque.

=back

Error descriptions, while typically longer than error names,
are intended for situations where
it is most convenient if they fit into a single line,
or at most two.
The Libmarpa API document contains a section on the Libmarpa
error codes.
and there the descriptions
are often longer and more detailed.

Error codes and error descriptions should be considered
valid
only if the most recently called Marpa thin method
indicated that it set the error code.
An application should assume that the
error codes and error descriptions will be overwritten by the
next call to 
any  thin interface method other than the L<< C<error()>
method|C<< $g->error() >> >>.

=head2 Failure and the error variables

A method indicates failure
either by throwing an exception
or by returning a value that indicates failure.
If a method follows the general pattern,
it indicates failure if and only if
its return value is less than or equal to -2.
Other methods indicate failure as stated in
their descriptions in this document.

Whenever a method indicates failure, that also
indicates that it has set the error variables.
On Libmarpa failures, the error code is set to the
Libmarpa error code.
On thin interface failure, the error code is
set to a Perl C<undef>.
For both Libmarpa and thin interface failures,
the error description is set to a text
that describes the error.

=head2 Success and the error variables

On success,
a method will take one of the following
three actions
with respect to the error variables:

=over 4

=item Reset the error code

A successful method
may set the error code to C<MARPA_ERR_NONE>,
together with an error description that indicates
there is no error.

=item Leave the error code as is

A successful method
may leave the error code and error
description as is.

=item Set an informational error code

A successful method may set a
Libmarpa error code to
a value other than C<MARPA_ERR_NONE>.
Error codes of this kind are called
informational error codes.
The phrase "error code" in this context
is something of a misnomer.
Informational error codes exist
as a convenience for some applications,
but typically are ignored.

=back

The Libmarpa API document sometimes specifies
what a Libmarpa method does with the error code
on success.
The Libmarpa API document always specifies
if and when a method sets an informational error code.
If Libmarpa API document is silent,
the application should regard it as unspecified
whether the error code is reset or left as is.

=head1 The general pattern

Most Marpa thin interface methods correspond directly
to a Libmarpa method,
and their behaviors are in most cases exactly the same.
These behaviors are called the "general pattern"
in this document.
To avoid repetition,
Marpa thin interface methods that follow
the general pattern exactly are
usually not
described explicitly in this document.

=head2 Method names

The name of a general pattern method is that of
its corresponding Libmarpa method,
minus the 8-letter prefix which indicates
its Libmarpa class.
For example,
the Marpa thin interface method that
corresponds to C<marpa_g_start_symbol_set>
is C<< $g->start_symbol_set() >>.
The class of the general pattern method
will be the Marpa thin class corresponding
to the time class
of the Libmarpa method.
For example, C<< $g->start_symbol_set() >>
will be in
the C<Marpa::R2::Thin:G> Perl class.

=head2 Arguments

Libmarpa's class instance methods
take an object of the their class
as their first ("self") argument.
Zero or more non-self arguments follow the self argument.
The arguments of the corresponding general pattern
Marpa thin method will be
the same, converted from C types to Perl as described next.
(This discussion follows
the convention used in L<perlobj>,
and considers the "self" object to
be a Perl method's first argument.)

In the general pattern,
every argument whose type is one
of Libmarpa's time classes is converted
to the corresponding Marpa thin interface class.
Arguments which belong to Libmarpa's numbered 
classes (C<Marpa_Earley_Set_ID>,
C<Marpa_Rank>,
C<Marpa_Rule_ID> and C<Marpa_Symbol_ID>)
are converted to Perl scalar integers.
C language C<int>'s are also
converted to Perl scalar integers.

The Marpa thin interface does
not recognize booleans, either in 
C or in Perl.
For example,
if a Perl true value is not a numeric
1, it will not be converted to a numeric
1 in C, even in a situation where
the Libmarpa method is clearly
looking for a boolean.
The intent is to allow for future extensions
to the Libmarpa interface that
accept and interpret other numeric values.

=head2 Return values

In the general pattern,
the return value from a Libmarpa method
will always either
belong to
one of Libmarpa's numbered classes,
or be a C language C<int>.
If the Libmarpa return value is a non-negative
integer,
the corresponding general pattern Marpa thin method
will return a numeric Perl scalar.
If the Libmarpa method returns -1,
its corresponding general pattern Marpa thin method
will return a Perl C<undef>.

=head2 General pattern failures

General pattern methods consider failure to be
a Libmarpa return value of -2 or less.
Failure is thrown if the throw setting is 1.
On unthrown failure, the return value
of the Libmarpa method will
be returned by the Marpa thin
method as a numeric Perl scalar.

=head2 An example of a general pattern method

Here is an example of a Libmarpa function
whose corresponding Marpa thin method follows the
general pattern.

=for Marpa::R2::Display
ignore: 1

  marpa_g_start_symbol_set (grammar, symbol_S);

=for Marpa::R2::Display::End

and here is the corresonding thin Marpa call:

=for Marpa::R2::Display
name: Thin example
normalize-whitespace: 1
partial: 1

    $grammar->start_symbol_set($symbol_S);

=for Marpa::R2::Display::End

=head1 Error recovery

Error recovery is as in the Libmarpa API,
with changes appropriate to adopt it to a Perl module.
We recall the concepts of application behavior and diagnostic
behavior from the Libmarpa API:
Application behaviors are those that normal applications may
expect, as specified in this and the Libmarpa API document.
Diagnostic behaviors are a subset of the application behaviors.
Diagnostic behaviors are those
that diagnostic or testing code may reasonably
attempt after an irrecoverable error.
Informally, application behaviors are promised,
while diagnostic behaviors are hoped for.
For a full discussion of application and diagnostic behaviors,
refer back to the Libmarpa API document.

Analogously to the Libmarpa API,
we call the object which caused a failure,
the failure object.
If the failure object is a time object,
its base grammar object is the grammar object it was
created from, whether directly, indirectly
or trivially.
A grammar object is considered to be created trivially from
itself.
If the failure object is a time object,
the failure grammar is the base grammar object of
the failure object.

In the following sections,
we adopted the definitions of library-recoverable,
ancestry-recoverable and fully recoverable failure
to make them
analogous to the
Libmarpa API's definitions of these terms.

=head2 Library-recoverable failure

In the thin interface, "library-recoverable failure" might be more properly be called
"module-recoverable failure".
We retain the term "library-recoverable failure"
for convenience in referring back to the Libmarpa API document.

When a thin wrapper corresponding to a Libmarpa method
has a library-recoverable failure the following application behaviors are no longer
available:

=over 4

=item *

Thin interface mutator and constructor method calls
on objects whose base grammar is the failure grammar.

=back

The following application behaviors remain available:

=over 4

=item *

All behaviors not in the thin interface,
including the Perl environment itself,
and all modules other than the thin interface.

=item *

All thin interface static method calls.

=item *

All thin interface accessor method calls,
and thin interface object destruction.

=item *

All thin interface constructor and mutator method calls
for objects whose base grammar is not the failure grammar.

=back

For more details on library-recoverability, refer to
the Libmarpa API document.

=head2 Ancestry-recoverable failure

When a thin wrapper corresponding to a Libmarpa method
has a ancestry-recoverable failure the following application behaviors are no longer
available:

=over 4

=item *

Thin interface mutator and constructor method calls
on on the failure object,
or on one of the descendants
of the failure object.

=back

The following application behaviors remain available:

=over 4

=item *

All behaviors not in the thin interface,
including the Perl environment itself,
and all packages other than the thin interface.

=item *

All thin interface static method calls.

=item *

All thin interface accessor method calls,
and thin interface object destruction.

=item *

All thin interface constructor and mutator method calls
for objects that are not the failure object,
or one of its descendants.

=back

For more details on ancestry-recoverability, refer to
the Libmarpa API document.

=head2 Fully recoverable failure

After a fully recoverable failure,
all application behaviors remain available.
For more details on fully recoverable failure, refer to
the Libmarpa API document.

=head1 Error methods

The thin interface to Libmarpa provides
error methods
more appropriate to the Perl
environment
than Libmarpa's own.
Calls to these methods are diagnostic behaviors.

=head2 C<< $g->error() >>

=for Marpa::R2::Display
name: Thin grammar error methods
normalize-whitespace: 1

    my ( $error_code, $error_description ) = $grammar->error();
    my @error_names = Marpa::R2::Thin::error_names();
    my $error_name = $error_names[$error_code];

=for Marpa::R2::Display::End

In scalar context,
the C<error()> method returns the error description.
In array context, it returns a 2-element array.
The first element of the array is the error code,
and the second element is the error description.
Applications should assume that
a call to any other Marpa thin method
will overwrite the error code and error description.
For C<error()> to successfully query
the error code or error description of a method,
C<error()> should be
the next Marpa thin interface method called.

=head2 C<< $g->error_clear() >>

The C<error_clear()> method follows the general pattern.

=head2 C<< $g->error_names() >>

For a synopsis, see L<< the section on
the C<< $g->error() >>
method|C<< $g->error() >> >>.
The C<error_names()> method returns a
B<reference> to an array of error names,
indexed by Libmarpa error code.

=head2 C<< $g->throw_set() >>

=for Marpa::R2::Display
name: Thin throw_set() example
normalize-whitespace: 1

    $grammar->throw_set(0);

=for Marpa::R2::Display::End

The C<throw_set()> method turns the throw flag
for the grammar on or off,
according to whether its argument is 1 or 0.
C<throw_set()> fails if its argument is
not a numeric 0 or 1.
C<throw_set()> itself never returns failure --
it always throws an exception.

=head2 Omitted configuration methods

All of the methods of Libmarpa's configuration
class are omitted in the Marpa thin interface.
The functions performed by Libmarpa's configuration
methods are handled in a more Perl-centric way
by the Marpa thin interface.

=head1 Grammar methods

=head2 C<< Marpa::R2::Thin::G->new() >>

=for Marpa::R2::Display
name: Thin example
partial: 1
normalize-whitespace: 1

    my $grammar = Marpa::R2::Thin::G->new( { if => 1 } );

=for Marpa::R2::Display::End

The one argument to the Marpa thin interface's
grammar constructor,
is a reference to a hash of named arguments.
On success,
the return value is a thin interface grammar object.
C<new()> does not obey the throw setting --
errors are always thrown.

Most applications should call the
C<force_valued()> method immediately after the call
of the C<new()> constructor.
Not doing so enables unvalued terminals,
which is a deprecated feature both in the thin
interface and the Libmarpa API.

At present the only named argument allowed is C<if>,
the interface number.
This argument is required and currently is required
to have a value of 1,
which specifies interface 1.
The intent of the C<if> argument is to provide
for backward compatibility in the future.

Although there is no error message or warning if the hash
ref argument
is omitted, new code should treat
the hash ref argument as a required argument.
Calling C<new()> without an argument is deprecated.
If the hash ref argument is omitted, the thin
layer uses interface 0.
Interface 0 cannot be specified directly,
and is deprecated.
The difference between interface 0 and interface 1
is that, in interface 0, the default throw setting
of the newly created grammar object
is unspecified.
(In fact, the interface 0 throw setting depends on an
undocumented and deprecated global variable.)

=head2 C<< $g->force_valued() >>

=for Marpa::R2::Display
name: Thin example
partial: 1
normalize-whitespace: 1

    $grammar->force_valued();

=for Marpa::R2::Display::End

The C<force_valued()> follows the general pattern.
Most applications should call the
C<force_valued()> method immediately after the
grammar's C<new()> constructor.
Not doing so enables unvalued terminals,
which is a deprecated feature both in the thin
interface and the Libmarpa API.

=head2 C<< $g->event() >>

=for Marpa::R2::Display
name: Thin event() example
normalize-whitespace: 1

    my ( $event_type, $value ) = $grammar->event( $event_ix++ );

=for Marpa::R2::Display::End

The C<event()> method returns a two-element array on success.
The first element is a string naming the event type,
and the second is a scalar representing its value.
The string for an event type is its macro name,
as given in the Libmarpa API document.

Some event types have an event "value".
All event values are numeric Perl scalars.
The number is either a symbol ID or a count,
as described in the Libmarpa API document.

The permissible range of event indexes can be
found with the Marpa thin interface's C<event_count()>
grammar method,
which corresponds to Libmarpa's
C<marpa_g_event_count()> method.
The thin interface's C<event_count()> method 
follows the general pattern.

Since C<event()> returns the event value whenever it
exists,
the Libmarpa C<marpa_g_event_value()> method is
unneeded.
The Libmarpa C<marpa_g_event_value()> method has
no corresponding Marpa thin interface method.

C<event()> obeys the throw setting.
On unthrown failure, C<event()> returns a Perl C<undef>.

=head2 C<< $g->rule_new() >>

=for Marpa::R2::Display
name: Thin example
partial: 1
normalize-whitespace: 1

    my $start_rule_id = $grammar->rule_new( $symbol_S, [$symbol_E] );

=for Marpa::R2::Display::End

The C<rule_new()> grammar method is
the Libmarpa thin interface method corresponding
to the C<marpa_g_rule_new()> method.
It takes two arguments, both required.
The first argument is a symbol ID representing the
rule's LHS,
and the second argument is a reference to an
array of symbol ID's.
The symbol ID's in the array represent the RHS.
On success,
the return value is the ID of the new rule.

C<rule_new()> obeys the throw setting.
On unthrown failure, it returns -2.

=head2 C<< $g->sequence_new() >>

=for Marpa::R2::Display
name: Thin sequence_new() example
normalize-whitespace: 1

    my $sequence_rule_id = $grammar->sequence_new(
            $symbol_S,
            $symbol_a,
            {   separator => $symbol_sep,
                proper    => 0,
                min       => 1
            }
        );

=for Marpa::R2::Display::End

The C<sequence_new()> grammar method is
the Libmarpa thin interface method corresponding
to the C<marpa_g_sequence_new()> method.
It takes three arguments, all required.
The first argument is a symbol ID representing the
sequence's LHS.
The second argument is a symbol ID representing the
sequence's RHS.
The third argument is a reference to a hash of named
arguments.

The hash of named arguments may be empty.
If not empty, its keys, and their values,
must be one of the following:

=over

=item C<separator>

The value of the C<separator> named argument
will be treated as an integer,
and passed as the separator ID argument
to the C<marpa_g_sequence_new()> method.
It defaults to -1.

=item C<proper>

If the value of C<proper> named argument
is a Perl true value,
the C<MARPA_PROPER_SEPARATION> flag
will be set in the flags passed
to the C<marpa_g_sequence_new()> method.
Otherwise, 
the C<MARPA_PROPER_SEPARATION> flag
will not be set.

=item C<min>

The value of the C<min> named argument
will be treated as an integer,
and passed as the C<min> argument
to the C<marpa_g_sequence_new()> method.
The C<min> argument indicates the minimum number of
repetitions of the sequence that are required.
It defaults to 1.

=back

On success,
the return value is
the rule ID of the new sequence.

Users should be aware that all sequences at
the Marpa thin interface level are "keep
separation".
This differs from the higher-level interface,
which discards separators by default.
At the 
Marpa thin interface level, it is up
to the programmer to discard separators,
if that is what is wanted.

C<sequence_new()> obeys the throw setting.
On unthrown failure, it returns -2.

=head2 C<< $g->precompute() >>

=for Marpa::R2::Display
name: Thin example
partial: 1
normalize-whitespace: 1

    $grammar->precompute();

=for Marpa::R2::Display::End

The C<precompute()> method follows the general pattern.
In addition to errors,
C<precompute()> also reports events.
Events are queried using the grammar's
C<event()> method.

As in the Libmarpa API, parsing with cycles
is deprecated.
This mean that treating C<MARPA_ERR_GRAMMAR_HAS_CYCLE> as a
fully recoverable failure is deprecated.
Instead,
C<MARPA_ERR_GRAMMAR_HAS_CYCLE> should be treated as
as a library-recoverable failure.

On success, C<precompute()> returns an event count.
But, even when there is an error,
C<precompute()> often reports
one or more events.
It is not safe to assume that no events occurred
unless C<precompute()> succeeds and reports
an event count of zero.

=head2 C<< $g->rule_rank() >>

The C<rule_rank()> method is based on
Libmarpa's C<marpa_g_rule_rank()> method.
Its argument is the rule ID,
and its return value is the rank,
or a -2 to indicate an unthrown error.

Note a return value of -2 is ambiguous -- it can
indicate that the rank was -2, or that a failure
occurred.
To distinguish the cases, the application can
look at the error code.
The error code
will be C<MARPA_ERR_NONE> if and only
if the call was successful.
The error code can be found using the L<< C<error()>
method|C<< $g->error() >> >>.
Applications may find it more convenient to have
C<rule_rank()> always throw its errors.

=head2 C<< $g->rule_rank_set() >>

The C<rule_rank_set()> method is based on
Libmarpa's C<marpa_g_rule_rank_set()> method.
Its two arguments are the rule ID and a rule rank.
Its return value is the new value of the rank,
or a -2 to indicate an unthrown error.

Note a return value of -2 is ambiguous -- it can
indicate that the rank was -2, or that a failure
occurred.
To distinguish the cases, the application can
look at the error code.
The error code
will be C<MARPA_ERR_NONE> if and only
if the call was successful.
The error code can be found using the L<< C<error()>
method|C<< $g->error() >> >>.
Applications may find it more convenient to have
C<rule_rank_set()> always throw its errors.

=head2 C<< $g->symbol_is_terminal_set() >>

=for Marpa::R2::Display
name: Thin symbol_is_terminal_set() example
normalize-whitespace: 1

    $grammar->symbol_is_terminal_set( $symbol_seq, 1 );

=for Marpa::R2::Display::End

The C<symbol_is_terminal_set()> method is deprecated.
It enables the LHS terminals feature, which is deprecated
in both the thin interface and the Libmarpa API.
The C<symbol_is_terminal_set()> method follows the general pattern.

=head2 Omitted grammar methods

The C<marpa_g_ref()>
and C<marpa_g_unref()> methods are omitted
because the Marpa thin interface performs
their function.
The C<marpa_g_event_value()> method is omitted
because its function is absorbed into
the thin interface's C<event()> grammar method.

=head2 General pattern methods

All grammar methods that are part of the Libmarpa external interface,
but that are not mentioned explicitly in this document,
are implemented
following the general pattern, as described
L<above|"The general pattern">.

=head1 Recognizer methods

=head2 C<< Marpa::R2::Thin::R->new() >>

=for Marpa::R2::Display
name: Thin example
partial: 1
normalize-whitespace: 1

    my $recce = Marpa::R2::Thin::R->new($grammar);

=for Marpa::R2::Display::End

The C<new()> method takes a Marpa thin grammar object
as its one argument.
On success, it returns a Marpa thin recognizer object.
C<new()> obeys the throw setting.
On unthrown failure, it returns a Perl C<undef>.

=head2 C<< $r->ruby_slippers_set() >>

=for Marpa::R2::Display
name: Thin ruby_slippers_set() example
normalize-whitespace: 1

    $recce->ruby_slippers_set(1);

=for Marpa::R2::Display::End

With an argument of 1,
the C<ruby_slippers_set()> method enables "Ruby Slippers" mode.
An argument of 0 disables "Ruby Slippers" mode.
By default, 
Ruby Slippers mode is disabled.
Note that this default (disabled) is
the opposite of that in the higher level L<Marpa::R2> interface.

The L<< C<alternative()>
method|C<< $r->alternative() >> >>
will only throw exceptions when 
"Ruby Slippers" mode is disabled and the throw flag is on.
One way of describing Ruby Slippers mode is as
an override of the throw setting, one which only applies
to the C<alternative()> method.

The C<ruby_slippers_set()> method itself does B<not>
obey the throw setting.
All failures by C<ruby_slippers_set()> are thrown
as exceptions.

=head2 C<< $r->alternative() >>

=for Marpa::R2::Display
name: Thin example
partial: 1
normalize-whitespace: 1

    $recce->alternative( $symbol_number, 2, 1 );

=for Marpa::R2::Display::End

In the Libmarpa API
the
C<alternative()> method returns an error
code,
with 
C<MARPA_ERR_NONE> being the code returned if there
was no error.
The C<alternative()> method will
throw the error code as an
exception if and only if all three 
of the following are true:

=over

=item * The base grammar's throw flag is on.

=item * The Ruby Slippers flag is off.

=item * The error code is not C<MARPA_ERR_NONE>.

=back

Of major interest is the error code
C<MARPA_ERR_UNEXPECTED_TOKEN_ID>,
which indicates that a token was not accepted because
its token ID was not one of those expected.
Catching and recovering
from this error is the basis of the Ruby Slippers parsing
technique.
For more on the Ruby Slippers flag,
see L<< C<ruby_slippers_set()>|C<< $r->ruby_slippers_set() >> >>.

=head2 C<< $r->terminals_expected() >>

=for Marpa::R2::Display
name: Thin terminals_expected() example
partial: 1
normalize-whitespace: 1

    my @terminals = $recce->terminals_expected();

=for Marpa::R2::Display::End

The C<terminals_expected()> method takes no arguments.
On success, it returns an array containing the
symbol ID's of the expected terminals.
Note that the array of expected terminal ID's may
be empty, so that an empty array is NOT a failure
indicator.
C<terminals_expected()> obeys the throw setting.
On unthrown failure,
C<terminals_expected()> returns a Perl C<undef>.

=head2 C<< $r->progress_item() >>

=for Marpa::R2::Display
name: Thin progress_item() example

    my $ordinal = $recce->latest_earley_set();
    $recce->progress_report_start($ordinal);
    ITEM: while (1) {
        my ($rule_id, $dot_position, $origin) = $recce->progress_item();
        last ITEM if not defined $rule_id;
        push @{$report}, [$rule_id, $dot_position, $origin];
    }
    $recce->progress_report_finish();

=for Marpa::R2::Display::End

The C<progress_item()> method takes no arguments.
On success, it returns an array of 3 elements:
the rule ID, the dot position, and the earley set ID
of the origin.
If there are no more items,
C<progress_item()> returns a Perl C<undef>.

C<progress_item()> obeys the throw setting.
On unthrown failure,
the rule ID element in the array returned by
C<progress_item()> will have a value of -2.

=head2 Omitted recognizer methods

Because the Marpa thin interface 
handles reference counting internally,
it does not implement methods
directly corresponding to
Libmarpa's C<marpa_r_ref()>
and C<marpa_r_unref()> methods.

There are Marpa thin methods
corresponding to
Libmarpa's C<marpa_r_earley_set_value()>
and C<marpa_r_earley_set_value_set()> methods,
but not to
Libmarpa's C<marpa_r_earley_set_values()>
and C<marpa_r_earley_set_values_set()> methods.
The difference between these is that the "values" form allows an
integer and a pointer value to be set,
while 
the "value" form allows only an integer to be set.
Perl applications which want to associate non-integer data with an Earley set
should create an array, and use the integer to index the array.
The elements of the array can contain arbitrary data.

The thin interface does not implement a way to set the Earley set pointer
value, because to do so would not add value.
The thin interface would have to track the reference
count of a pointer,
and this can done as easily and efficiently,
and with more flexibility, at the Perl level.

=head2 Methods not mentioned

All recognizer methods that are part of the Libmarpa external interface,
but that are not mentioned explicitly in this document,
are implemented
following the general pattern, as described
L<above|"The general pattern">.

=head1 Bocage methods

=head2 C<< Marpa::R2::Thin::B->new() >>

=for Marpa::R2::Display
name: Thin example
partial: 1
normalize-whitespace: 1

    my $latest_earley_set_ID = $recce->latest_earley_set();
    my $bocage = Marpa::R2::Thin::B->new( $recce, $latest_earley_set_ID );

=for Marpa::R2::Display::End

The C<new()> method takes a Marpa thin recognizer object
as its one argument.
On success, it returns a Marpa thin bocage object.
C<new()> obeys the throw setting.
On unthrown failure, it returns a Perl C<undef>.

=head2 Omitted bocage methods

Because the Marpa thin interface 
handles reference counting internally,
it does not implement methods
directly corresponding to
Libmarpa's C<marpa_b_ref()>
and C<marpa_b_unref()> methods.

=head2 Methods not mentioned

All bocage methods that are part of the Libmarpa external interface,
but that are not mentioned explicitly in this document,
are implemented
following the general pattern, as described
L<above|"The general pattern">.

=head1 Ordering methods

=head2 C<< Marpa::R2::Thin::O->new() >>

=for Marpa::R2::Display
name: Thin example
partial: 1
normalize-whitespace: 1

    my $order = Marpa::R2::Thin::O->new($bocage);

=for Marpa::R2::Display::End

The C<new()> method takes a Marpa thin bocage object
as its one argument.
On success, it returns a Marpa thin ordering object.
C<new()> obeys the throw setting.
On unthrown failure, it returns a Perl C<undef>.

=head2 Omitted ordering methods

Because the Marpa thin interface 
handles reference counting internally,
it does not implement methods
directly corresponding to
Libmarpa's C<marpa_o_ref()>
and C<marpa_o_unref()> methods.

=head2 Methods not mentioned

All ordering methods that are part of the Libmarpa external interface,
but that are not mentioned explicitly in this document,
are implemented
following the general pattern, as described
L<above|"The general pattern">.

=head1 Tree methods

=head2 C<< Marpa::R2::Thin::T->new() >>

=for Marpa::R2::Display
name: Thin example
partial: 1
normalize-whitespace: 1

    my $tree = Marpa::R2::Thin::T->new($order);

=for Marpa::R2::Display::End

The C<new()> method takes a Marpa thin ordering object
as its one argument.
On success, it returns a Marpa thin tree object.
C<new()> obeys the throw setting.
On unthrown failure, it returns a Perl C<undef>.

=head2 Omitted tree methods

Because the Marpa thin interface 
handles reference counting internally,
it does not implement methods
directly corresponding to
Libmarpa's C<marpa_t_ref()>
and C<marpa_t_unref()> methods.

=head2 Methods not mentioned

All tree methods that are part of the Libmarpa external interface,
but that are not mentioned explicitly in this document,
are implemented
following the general pattern, as described
L<above|"The general pattern">.

=head1 Value methods

=head2 C<< Marpa::R2::Thin::V->new() >>

=for Marpa::R2::Display
name: Thin example
partial: 1
normalize-whitespace: 1

    my $valuator = Marpa::R2::Thin::V->new($tree);

=for Marpa::R2::Display::End

The C<new()> method takes a Marpa thin tree object
as its one argument.
On success, it returns a Marpa thin value object.
C<new()> obeys the throw setting.
On unthrown failure, it returns a Perl C<undef>.

=head2 C<< $v->location() >>

=for Marpa::R2::Display
name: Thin location() example
normalize-whitespace: 1

    $type = $valuator->step_type();
    my ( $start, $end ) = $valuator->location();
    if ( $type eq 'MARPA_STEP_RULE' ) {
        my ($rule_id) = @step_data;
        $locations_report .= "Rule $rule_id is from $start to $end\n";
    }
    if ( $type eq 'MARPA_STEP_TOKEN' ) {
        my ($token_id) = @step_data;
        $locations_report .= "Token $token_id is from $start to $end\n";
    }
    if ( $type eq 'MARPA_STEP_NULLING_SYMBOL' ) {
        my ($symbol_id) = @step_data;
        $locations_report
            .= "Nulling symbol $symbol_id is from $start to $end\n";
    }


=for Marpa::R2::Display::End

The C<location()> method takes no arguments.
The C<location()> method always succeeds,
returning either an empty array
or an array of two elements.

=over 4

=item *

If the last step was C<MARPA_STEP_RULE>,
the array contains the locations where the rule starts
and ends,
as returned
by the Libmarpa methods C<marpa_v_rule_start_es_id()>
and C<marpa_v_es_id()>.

=item *

It the last step was C<MARPA_STEP_TOKEN>,
the array contains the locations where the token starts
and ends,
as returned
by the Libmarpa methods C<marpa_v_token_start_es_id()>
and C<marpa_v_es_id()>.

=item *

It the last step was C<MARPA_STEP_NULLING_SYMBOL>,
the array contains the locations where the token starts
and ends,
as returned
by the Libmarpa methods C<marpa_v_token_start_es_id()>
and C<marpa_v_es_id()>.

=item *

In any other case,
the array is empty.

=back

=head2 C<< $v->step() >>

=for Marpa::R2::Display
name: Thin example
partial: 1
normalize-whitespace: 1

    my ( $type, @step_data ) = $valuator->step();

=for Marpa::R2::Display::End

The C<step()> method takes no arguments.
On success, C<step()>
returns an array, whose contents are as follows:

=over 4

=item C<MARPA_STEP_RULE>

If the step type is C<MARPA_STEP_RULE>, C<step()>
returns an array of 4 elements.  These will be,
in order:

=over 4

=item *

The string "C<MARPA_STEP_RULE>".

=item *

The rule id, as returned
by the Libmarpa method C<marpa_v_rule_id()>.

=item *

The stack location where the child values
of the rule begin,
as returned
by the Libmarpa method C<marpa_v_token_arg_0()>.
This is also the stack location to which the result
should be written.

=item *

The stack location where the child values
of the rule end,
as returned
by the Libmarpa method C<marpa_v_token_arg_n()>.

=back

=item C<MARPA_STEP_TOKEN>

If the step type is C<MARPA_STEP_TOKEN>, C<step()>
returns an array of 4 elements.  These will be,
in order:

=over 4

=item *

The string "C<MARPA_STEP_TOKEN>".

=item *

The token id, as returned
by the Libmarpa method C<marpa_v_token()>.

=item *

The token value, as returned
by the Libmarpa method C<marpa_v_token_value()>.

=item *

The stack location to which the token's
value should be written,
as returned
by the Libmarpa method C<marpa_v_result()>.

=back

As a reminder, Libmarpa's token values are always integers.
Applications will often have a richer or different
semantics for token values.
One approach such applications can take is
to use
Libmarpa's token values as indexes into an array.

=item C<MARPA_STEP_NULLING_SYMBOL>

If the step type is C<MARPA_STEP_NULLING_SYMBOL>, C<step()>
returns an array of 3 elements.  These will be,
in order:

=over 4

=item *

The string "C<MARPA_STEP_NULLING_SYMBOL>".

=item *

The ID of the nulling symbol, as returned
by the Libmarpa method C<marpa_v_symbol()>.

=item *

The stack location to which the nulling
symbol's value should be written,
as returned
by the Libmarpa method C<marpa_v_result()>.

=back

=item C<MARPA_STEP_INACTIVE>

If the step type is C<MARPA_STEP_INACTIVE>, C<step()> returns
an empty array.

=back

C<step()> obeys the throw setting.
On unthrown failure,
C<step()> returns an array whose only
element is a
string not reserved by Libmarpa.
A string is not reserved by Libmarpa if it does
not begin with "C<MARPA_>" in one of its
capitalization variants.
The string will usually be a description of the error.

=head2 C<< $v->step_type() >>

=for Marpa::R2::Display
name: Thin location() example
partial: 1
normalize-whitespace: 1

    $type = $valuator->step_type();

=for Marpa::R2::Display::End

The C<step_type()> method takes no arguments.
On success, C<step_type()>
returns the string indicating the type of the last
Libmarpa valuator step.
If the last call of the
L<< C<step()>
method|C<< $v->step() >> >> succeeded,
the string returned by C<step_type()> will
be the same as the one that was the first
element of the array returned by C<step()>.

C<step_type()> obeys the throw setting.
On unthrown failure,
C<step()> returns an array whose only
element is a
string not reserved by Libmarpa.
A string is not reserved by Libmarpa if it does
not begin with "C<MARPA_>" in one of its
capitalization variants.
The string will usually be a description of the error.

=head2 Omitted value methods

Because the Marpa thin interface 
handles reference counting internally,
it does not implement methods
directly corresponding to
Libmarpa's C<marpa_v_ref()>
and C<marpa_v_unref()> methods.
The step accessor macros are folded into the thin interface's
C<< $v->step() >>
and C<< $v->location() >>
methods.
For this reason,
no thin interface macro corresponds directly to most
of the individual step accessors.

=head2 Methods not mentioned

All value methods that are part of the Libmarpa external interface,
but that are not mentioned explicitly in this document,
are implemented
following the general pattern, as described
L<above|"The general pattern">.

=head1 Example

=for Marpa::R2::Display
name: Thin example
normalize-whitespace: 1

    my $grammar = Marpa::R2::Thin::G->new( { if => 1 } );
    $grammar->force_valued();
    my $symbol_S = $grammar->symbol_new();
    my $symbol_E = $grammar->symbol_new();
    $grammar->start_symbol_set($symbol_S);
    my $symbol_op     = $grammar->symbol_new();
    my $symbol_number = $grammar->symbol_new();
    my $start_rule_id = $grammar->rule_new( $symbol_S, [$symbol_E] );
    my $op_rule_id =
        $grammar->rule_new( $symbol_E, [ $symbol_E, $symbol_op, $symbol_E ] );
    my $number_rule_id = $grammar->rule_new( $symbol_E, [$symbol_number] );
    $grammar->precompute();

    my $recce = Marpa::R2::Thin::R->new($grammar);
    $recce->start_input();

    # The numbers from 1 to 3 are themselves --
    # that is, they index their own token value.
    # Important: zero cannot be itself!

    my @token_values         = ( 0 .. 3 );
    my $zero                 = -1 + push @token_values, 0;
    my $minus_token_value    = -1 + push @token_values, q{-};
    my $plus_token_value     = -1 + push @token_values, q{+};
    my $multiply_token_value = -1 + push @token_values, q{*};

    $recce->alternative( $symbol_number, 2, 1 );
    $recce->earleme_complete();
    $recce->alternative( $symbol_op, $minus_token_value, 1 );
    $recce->earleme_complete();
    $recce->alternative( $symbol_number, $zero, 1 );
    $recce->earleme_complete();
    $recce->alternative( $symbol_op, $multiply_token_value, 1 );
    $recce->earleme_complete();
    $recce->alternative( $symbol_number, 3, 1 );
    $recce->earleme_complete();
    $recce->alternative( $symbol_op, $plus_token_value, 1 );
    $recce->earleme_complete();
    $recce->alternative( $symbol_number, 1, 1 );
    $recce->earleme_complete();

    my $latest_earley_set_ID = $recce->latest_earley_set();
    my $bocage        = Marpa::R2::Thin::B->new( $recce, $latest_earley_set_ID );
    my $order         = Marpa::R2::Thin::O->new($bocage);
    my $tree          = Marpa::R2::Thin::T->new($order);
    my @actual_values = ();
    while ( $tree->next() ) {
        my $valuator = Marpa::R2::Thin::V->new($tree);
        my @stack = ();
        STEP: while ( 1 ) {
            my ( $type, @step_data ) = $valuator->step();
            last STEP if not defined $type;
            if ( $type eq 'MARPA_STEP_TOKEN' ) {
                my ( undef, $token_value_ix, $arg_n ) = @step_data;
                $stack[$arg_n] = $token_values[$token_value_ix];
                next STEP;
            }
            if ( $type eq 'MARPA_STEP_RULE' ) {
                my ( $rule_id, $arg_0, $arg_n ) = @step_data;
                if ( $rule_id == $start_rule_id ) {
                    my ( $string, $value ) = @{ $stack[$arg_n] };
                    $stack[$arg_0] = "$string == $value";
                    next STEP;
                }
                if ( $rule_id == $number_rule_id ) {
                    my $number = $stack[$arg_0];
                    $stack[$arg_0] = [ $number, $number ];
                    next STEP;
                }
                if ( $rule_id == $op_rule_id ) {
                    my $op = $stack[ $arg_0 + 1 ];
                    my ( $right_string, $right_value ) = @{ $stack[$arg_n] };
                    my ( $left_string,  $left_value )  = @{ $stack[$arg_0] };
                    my $value;
                    my $text = '(' . $left_string . $op . $right_string . ')';
                    if ( $op eq q{+} ) {
                        $stack[$arg_0] = [ $text, $left_value + $right_value ];
                        next STEP;
                    }
                    if ( $op eq q{-} ) {
                        $stack[$arg_0] = [ $text, $left_value - $right_value ];
                        next STEP;
                    }
                    if ( $op eq q{*} ) {
                        $stack[$arg_0] = [ $text, $left_value * $right_value ];
                        next STEP;
                    }
                    die "Unknown op: $op";
                } ## end if ( $rule_id == $op_rule_id )
                die "Unknown rule $rule_id";
            } ## end if ( $type eq 'MARPA_STEP_RULE' )
            die "Unexpected step type: $type";
        } ## end while ( my ( $type, @step_data ) = $valuator->step() )
        push @actual_values, $stack[0];
    } ## end while ( $tree->next() )

=for Marpa::R2::Display::End

=head1 Copyright and License

=for Marpa::R2::Display
ignore: 1

  Copyright 2022 Jeffrey Kegler
  This file is part of Marpa::R2.  Marpa::R2 is free software: you can
  redistribute it and/or modify it under the terms of the GNU Lesser
  General Public License as published by the Free Software Foundation,
  either version 3 of the License, or (at your option) any later version.

  Marpa::R2 is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser
  General Public License along with Marpa::R2.  If not, see
  http://www.gnu.org/licenses/.

=for Marpa::R2::Display::End

=cut

# Local Variables:
#   mode: cperl
#   cperl-indent-level: 4
#   fill-column: 100
# End:
# vim: expandtab shiftwidth=4:
