#ifndef SIMPLE_PARSER_H
#define SIMPLE_PARSER_H
/*
   Copyright (c) 2024, MariaDB

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; version 2 of
   the License.

   This program 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 General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335  USA
*/


#include "simple_tokenizer.h"

/*
  A set of templates for constructing a recursive-descent LL(1) parser.
  This code utilizes the "Policy Based Design" approach. For details see:
  https://en.wikipedia.org/wiki/Modern_C%2B%2B_Design

  One is supposed to define classes corresponding to grammar productions.
  The class should inherit from the grammar rule template. For example, a
  grammar rule

    foo := bar, baz

  is implemented with

    class Bar ... ; // "bar" is parsed into Bar object
    class Baz ... ; // "baz" is parsed into Baz object

    // "foo" is parsed into a Foo object.
    class Foo: public Parser_templates::AND2<PARSER_Impl, Bar, Baz> {
      using AND2::AND2;
      ...
    };

  Parsing code is generated by inheriting AND2's constructors with "using" like
  shown above. All grammar rule-based classes should also have
  - a capability to construct an "empty"(i.e. invalid) object with the default
    constructor. This will be invoked when parsing fails.
  - operator bool() which returns true if the object is non-empty (i.e. valid)
    and false otherwise.

  Parsing is done by constructing parser output from the parser object:

    Foo parsed_output(parser);

  PARSER_Impl here is a class implementing a tokenizer and error condition
  storage, like Extended_string_tokenizer.

  Steps to make your own parser:

  First of all, you implement a tokenizer class.
  It can derive from Extended_string_tokenizer.

  See for examples:
  - class Tokenizer in item_numconvfunc.cc
  - class Optimizer_hint_tokenizer in opt_hints_parser.h

  The tokenizer class should implement:
  - a enum TokenID enumerating all possible tokens
  - a class Token. Normally it should contain two components:
    * a const string pointer with length,
      they will point to the fragment of the parsed text corresponding
      to each token returned by the tokenizer
    * a TokenID
  - a method get_token()

  On the next step you implement a parser class.
  See for examples:
  - class item_numconvfunc.cc in item_numconvfunc.cc
  - class Optimizer_hint_parser in opt_hints_parser.h

  The parser class should derive from the tokeniner class
  and from the clas Parser_templates. The parser class should implement:
  - a method empty_token()
  - a method null_token()
  - a method shift() - returning the current lookahead tokend and
    loading the next lookahead token into the member m_look_ahead_token.
  - a method Token(TokenID id) - checking the current looakead token ID
    and doing shift if it matches the current lookahead token
    in m_look_ahead_token.
  - a set of grammar rules using templates implemented in this file
*/

/*
  A future change proposal:
  Let's change all rule constructors to have a "const Parser &p" parameter.
  This will help to avoid having two versions of empty:
   - empty(const Parser &p)
   - empty()
*/

class Parser_templates
{
protected:

  /*
    Containers to collect parsed data into the goal structures.
    These classes are needed to avoid a boiler plate code.
  */

  /*
    CONTAINER1 wraps a user defined container class A
    (designed to store some grammar branch) in the way to make
    class A suitable for passing to OR_CONTAINER* by adding some common
    (boiler plate) method implementations, e.g:
    - deleting copying constructor and operator=
    - implementing moving constructor and operator=
    - implementing methods empty()
    Unlike OR_CONTAINER* (see below), CONTAINER1 assumes that A derives
    only from one parent class.
  */

  template<class PARSER, class AParent, class A>
  class CONTAINER1: public A
  {
    using SELF= CONTAINER1;
    using A::A;
  public:
    // Delete copying
    CONTAINER1(const SELF & rhs) = delete;
    SELF & operator=(const SELF & rhs) = delete;
    // Initialization from itself
    CONTAINER1(SELF && rhs) = default;
    SELF & operator=(SELF && rhs) = default;
    // Initialization from its components
    explicit CONTAINER1(A && rhs) :A(std::move(rhs)) { }

    // Generating empty values
    static SELF empty(const PARSER &p)
    {
      return SELF(A(AParent::Container::empty(p)));
    }
    static SELF empty()
    {
      return SELF(A(AParent::Container::empty()));
    }
  };

  /*
    OR_CONTAINER* to be passed as a CONTANER parameter to the
    ORxC parsing templates. OR_CONTAINER* derives from parts (components),
    which store the data parsed by alternative branches in the grammar.
    When one part is initialized from some data, all other parts are
    initialized to the value returned by the empty() method of the
    corresponding part.
  */

  // Make a single container from two other containers suitable for ORxC
  template<class PARSER, class AB, class A, class B>
  class OR_CONTAINER2: public AB
  {
    using SELF= OR_CONTAINER2;
    static_assert(std::is_base_of_v<A, AB>, "AB must derive from A");
    static_assert(std::is_base_of_v<B, AB>, "AB must derive from B");
    static_assert(std::negation_v<std::is_copy_constructible<AB>>,
                  "Invalid use of OR_CONTAINER2");
  public:
    using AB::AB;
    // Initialization on parse error
    OR_CONTAINER2()
     :AB(A(), B())
    { }
    // Initialization from its components
    OR_CONTAINER2(A && rhs)
     :AB(std::move(rhs),
         B::Container::empty())
    { }
    OR_CONTAINER2(B && rhs)
     :AB(A::Container::empty(),
         std::move(rhs))
    { }
    // Delete copying
    OR_CONTAINER2(const SELF & rhs) = delete;
    SELF & operator=(const SELF & rhs) = delete;
    // Initialization from itself
    OR_CONTAINER2(SELF && rhs) = default;
    SELF & operator=(SELF && rhs) = default;
    // Generating empty values
    explicit OR_CONTAINER2(AB && rhs) :AB(std::move(rhs)) { }
    static SELF empty(const PARSER &p)
    {
      return SELF(AB(A::Container::empty(p), B::Container::empty(p)));
    }
    static SELF empty()
    {
      return SELF(AB(A::Container::empty(), B::Container::empty()));
    }
  };


  // Make a single container from three other containers suitable for ORxC
  template<class PARSER, class ABC, class A, class B, class C>
  class OR_CONTAINER3: public ABC
  {
    using SELF= OR_CONTAINER3;
    static_assert(std::is_base_of_v<A, ABC>, "ABC must derive from A");
    static_assert(std::is_base_of_v<B, ABC>, "ABC must derive from B");
    static_assert(std::is_base_of_v<C, ABC>, "ABC must derive from C");
    static_assert(std::negation_v<std::is_copy_constructible<ABC>>,
                  "Invalid use of OR_CONTAINER3");
  public:
    using ABC::ABC;

    // Initialization on parse error
    OR_CONTAINER3()
     :ABC(A(), B(), C())
    { }
    // Initialization from its components
    OR_CONTAINER3(A && rhs)
     :ABC(std::move(rhs),
          B::Container::empty(),
          C::Container::empty())
    { }
    OR_CONTAINER3(B && rhs)
     :ABC(A::Container::empty(),
          std::move(rhs),
          C::Container::empty())
    { }
    OR_CONTAINER3(C && rhs)
     :ABC(A::Container::empty(),
          B::Container::empty(),
          std::move(rhs))
    { }
    explicit OR_CONTAINER3(ABC && rhs) :ABC(std::move(rhs)) { }
    // Delete copying
    OR_CONTAINER3(const SELF & rhs) = delete;
    SELF & operator=(const SELF & rhs) = delete;
    // Initialization from itself
    OR_CONTAINER3(SELF && rhs) = default;
    SELF & operator=(SELF && rhs) = default;
    // Gerating empty values
    static SELF empty(const PARSER &p)
    {
      return SELF(ABC(A::Container::empty(p),
                      B::Container::empty(p),
                      C::Container::empty(p)));
    }
    static SELF empty()
    {
      return SELF(ABC(A::Container::empty(),
                      B::Container::empty(),
                      C::Container::empty()));
    }
  };


  // Make a single container from four other containers suitable for ORxC
  template<class PARSER, class ABCD, class A, class B, class C, class D>
  class OR_CONTAINER4: public ABCD
  {
    using SELF= OR_CONTAINER4;
    static_assert(std::is_base_of_v<A, ABCD>, "ABCD must derive from A");
    static_assert(std::is_base_of_v<B, ABCD>, "ABCD must derive from B");
    static_assert(std::is_base_of_v<C, ABCD>, "ABCD must derive from C");
    static_assert(std::is_base_of_v<C, ABCD>, "ABCD must derive from D");
    static_assert(std::negation_v<std::is_copy_constructible<ABCD>>,
                  "Invalid use of OR_CONTAINER4");
  public:
    using ABCD::ABCD;
    // Initialization on parse error
    OR_CONTAINER4()
     :ABCD(A(), B(), C(), D())
    { }
    // Initialization from its components
    OR_CONTAINER4(A && rhs)
     :ABCD(std::move(rhs),
           B::Container::empty(),
           C::Container::empty(),
           D::Container::empty())
    { }
    OR_CONTAINER4(B && rhs)
     :ABCD(A::Container::empty(),
           std::move(rhs),
           C::Container::empty(),
           D::Container::empty())
    { }
    OR_CONTAINER4(C && rhs)
     :ABCD(A::Container::empty(),
           B::Container::empty(),
           std::move(rhs),
           D::Container::empty())
    { }
    OR_CONTAINER4(D && rhs)
     :ABCD(A::Container::empty(),
           B::Container::empty(),
           C::Container::empty(),
           std::move(rhs))
    { }
    explicit OR_CONTAINER4(ABCD && rhs) :ABCD(std::move(rhs)) { }
    // Delete copying
    OR_CONTAINER4(const SELF & rhs) = delete;
    SELF & operator=(const SELF & rhs) = delete;
    // Initializing from itself
    OR_CONTAINER4(SELF && rhs) = default;
    SELF & operator=(SELF && rhs) = default;
    // Generating empty values
    static SELF empty(const PARSER &p)
    {
      return SELF(ABCD(A::Container::empty(p),
                       B::Container::empty(p),
                       C::Container::empty(p),
                       D::Container::empty(p)));
    }
    static SELF empty()
    {
      return SELF(ABCD(A::Container::empty(),
                       B::Container::empty(),
                       C::Container::empty(),
                       D::Container::empty()));
    }
  };



  // Templates to parse common rule sequences


  /*
    A parser for an optional rule:
      opt_rule ::= [ rule ]

    Template parameters:
    - PARSER     - the main parser class
    - RULE_PARSE - the rule which we want to make optional in some grammar
  */
  template<class PARSER, class RULE_PARSER>
  class OPT: public RULE_PARSER
  {
  public:
    OPT() = default;

#ifdef SIMPLE_PARSER_V2
    // Delete copying
    OPT(const OPT & rhs) = delete;
    OPT & operator=(const OPT & rhs) = delete;
    // Assigning from itself
    OPT(OPT && rhs) = default;
    OPT & operator=(OPT && rhs) = default;
#endif
    OPT(PARSER *p)
     :RULE_PARSER(p)
    {
      if (!RULE_PARSER::operator bool() && !p->is_error())
      {
        RULE_PARSER::operator=(RULE_PARSER::empty(*p));
        DBUG_ASSERT(RULE_PARSER::operator bool());
      }
      else if (p->is_error() && RULE_PARSER::operator bool())
      {
#ifdef SIMPLE_PARSER_V2
        /*
          RULE_PARSER is responsible to implement operator=
          in the way that it frees all allocated memory.
        */
        RULE_PARSER::operator=(RULE_PARSER());
        DBUG_ASSERT(!RULE_PARSER::operator bool());
#endif
      }
    }
  };



  /*
    A rule consisting of a single token, e.g.:
      rule ::= @
      rule ::= IDENT
  */
  template<class PARSER, typename PARSER::TokenID tid>
  class TokenParser: public PARSER::Token
  {
  public:
    TokenParser()
    { }
#ifdef SIMPLE_PARSER_V2
    TokenParser(TokenParser && rhs) = default;
    TokenParser & operator=(TokenParser && rhs) = default;
#endif
    TokenParser(const class PARSER::Token &tok) = delete;
    TokenParser & operator=(const class PARSER::Token &tok) = delete;
    explicit TokenParser(class PARSER::Token &&tok)
     :PARSER::Token(std::move(tok))
    { }
    TokenParser & operator=(const class PARSER::Token &&tok)
    {
      PARSER::Token::operator=(std::move(tok));
      return *this;
    }
    TokenParser(PARSER *p)
     :PARSER::Token(p->token(tid))
    { }
    static TokenParser empty(const PARSER &p)
    {
      return TokenParser(p.empty_token());
    }
    static TokenParser empty()
    {
      return TokenParser(PARSER::Token::empty());
    }
    using Opt= OPT<PARSER, TokenParser>;
  };


  /*
    A rule consisting of a choice of multiple tokens
      rule ::= TOK1 | TOK2 | TOK3

    Which tokens are good or wrong for this rule is determined by
    the template parameter class COND which must have a static method:
      bool allowed_token_id(TokenID id).
    It gets the lookahead token id as a parameter and returns:
    - true for good tokens
    - false for bad tokens
  */
  template<class PARSER, class COND>
  class TokenChoice: public PARSER::Token
  {
  public:
    TokenChoice()
    { }
    /*
      Pass the parser's lookahead token id to COND::allowed_token_id()
      to determine if it's a good or bad token.
    */
    TokenChoice(PARSER *p)
     :PARSER::Token(COND::allowed_token_id(p->look_ahead_token_id()) ?
                    p->shift() :
                    p->null_token())
    {
      DBUG_ASSERT(!p->is_error() || !PARSER::Token::operator bool());
    }
    TokenChoice(const class PARSER::Token &tok)
     :PARSER::Token(tok)
    { }
    static TokenChoice empty(const PARSER &parser)
    {
      return TokenChoice(parser.empty_token());
    }
    static TokenChoice empty()
    {
      return PARSER::Token::empty();
    }
    using Opt= OPT<PARSER, TokenChoice>;
  };

  template<class PARSER, typename PARSER::TokenID a,
                         typename PARSER::TokenID b>
  class TokenChoiceCond2
  {
  public:
    static bool allowed_token_id(typename PARSER::TokenID id)
    { return id == a || id == b; }
  };

  template<class PARSER, typename PARSER::TokenID a,
                         typename PARSER::TokenID b,
                         typename PARSER::TokenID c>
  class TokenChoiceCond3
  {
  public:
    static bool allowed_token_id(typename PARSER::TokenID id)
    { return id == a || id == b || id == c; }
  };

  /*
    A rule consisting of two other rules in a row:
      rule ::= rule1 rule2
  */
  template<class PARSER, class A, class B>
  class AND2: public A, public B
  {
  public:
    AND2() = default;
    // Delete copying
    AND2(const AND2 & rhs) = delete;
    AND2 & operator=(const AND2 & rhs) = delete;
    // Initializing from itself
    AND2(AND2 && rhs) = default;
    AND2 & operator=(AND2 &&rhs) = default;
    // Initializing from its components
    AND2(A &&a, B &&b)
     :A(std::move(a)), B(std::move(b))
    { }
    AND2(PARSER *p)
     :A(p),
      B(A::operator bool() ? B(p) : B())
    {
      if (A::operator bool() && !B::operator bool())
      {
        p->set_syntax_error();
        // Reset A to have A, B reported as "false" by their operator bool()
        A::operator=(std::move(A()));
      }
      DBUG_ASSERT(!operator bool() || !p->is_error());
    }
    explicit operator bool() const
    {
      return A::operator bool() && B::operator bool();
    }
    static AND2 empty(const PARSER &p)
    {
      return AND2(A::empty(p), B::empty(p));
    }
    using Opt= OPT<PARSER, AND2<PARSER, A, B>>;
  };


  /*
    A rule consisting of three other rules in a row:
      rule ::= rule1 rule2 rule3
  */
  template<class PARSER, class A, class B, class C>
  class AND3: public A, public B, public C
  {
  public:
    AND3() = default;
    // Delete copying
    AND3(const AND3 & rhs) = delete;
    AND3 & operator=(const AND3 & rhs) = delete;
    // Initializing from itself
    AND3(AND3 && rhs) = default;
    AND3 & operator=(AND3 &&rhs) = default;
    // Initializing from components
    AND3(A &&a, B &&b, C &&c)
     :A(std::move(a)), B(std::move(b)), C(std::move(c))
    { }
    AND3(PARSER *p)
     :A(p),
      B(A::operator bool() ? B(p) : B()),
      C(A::operator bool() && B::operator bool() ? C(p) : C())
    {
      if (A::operator bool() && (!B::operator bool() || !C::operator bool()))
      {
        p->set_syntax_error();
        // Reset A to have A, B, C reported as "false" by their operator bool()
        A::operator=(std::move(A()));
        B::operator=(std::move(B()));
        C::operator=(std::move(C()));
      }
      DBUG_ASSERT(!operator bool() || !p->is_error());
    }
    explicit operator bool() const
    {
      return A::operator bool() && B::operator bool() && C::operator bool();
    }
    static AND3 empty(const PARSER &p)
    {
      return AND3(A::empty(p), B::empty(p), C::empty(p));
    }
  };


  /*
    A rule consisting of four other rules in a row:
      rule ::= rule1 rule2 rule3 rule4
  */
  template<class PARSER, class A, class B, class C, class D>
  class AND4: public A, public B, public C, public D
  {
  public:
    AND4() = default;
    // Delete copying
    AND4(const AND4 & rhs) = delete;
    AND4 & operator=(const AND4 & rhs) = delete;
    // Initializing from itself
    AND4(AND4 && rhs) = default;
    AND4 & operator=(AND4 &&rhs) = default;
    // Initializing from components
    AND4(A &&a, B &&b, C &&c, D &&d)
     :A(std::move(a)), B(std::move(b)), C(std::move(c)), D(std::move(d))
    { }
    AND4(PARSER *p)
     :A(p),
      B(A::operator bool() ? B(p) : B()),
      C(A::operator bool() && B::operator bool() ? C(p) : C()),
      D(A::operator bool() && B::operator bool() && C::operator bool() ?
        D(p) : D())
    {
      if (A::operator bool() &&
          (!B::operator bool() || !C::operator bool() || !D::operator bool()))
      {
        p->set_syntax_error();
        // Reset A to have A, B, C reported as "false" by their operator bool()
        A::operator=(A());
        B::operator=(B());
        C::operator=(C());
        D::operator=(D());
      }
      DBUG_ASSERT(!operator bool() || !p->is_error());
    }
    explicit operator bool() const
    {
      return A::operator bool() && B::operator bool() &&
             C::operator bool() && D::operator bool();
    }
    static AND4 empty(const PARSER &p)
    {
      return AND4(A::empty(p), B::empty(p), C::empty(), D::empty());
    }
  };


  /*
    A rule consisting of a choice of rwo rules:
      rule ::= rule1 | rule2

    For the cases when the two branches have incompatible storage.
  */
  template<class PARSER, class A, class B>
  class OR2: public A, public B
  {
  public:
    OR2() = default;
    // Delete copying
    OR2(const OR2 & rhs) = delete;
    OR2 & operator=(const OR2 & rhs) = delete;
    // Initializing from itself
    OR2(OR2 &&rhs) = default;
    OR2 & operator=(OR2 &&rhs) = default;
    // Initializing from components
    OR2(A &&a, B &&b)
     :A(std::move(a)), B(std::move(b))
    { }
    OR2(A && rhs)
     :A(std::move(rhs)), B()
    { }
    OR2(B && rhs)
     :A(), B(std::move(rhs))
    { }
    OR2(PARSER *p)
     :A(p), B(A::operator bool() ? B() :B(p))
    {
      DBUG_ASSERT(!operator bool() || !p->is_error());
    }
    explicit operator bool() const
    {
      return A::operator bool() || B::operator bool();
    }
    static OR2 empty(const PARSER &p)
    {
      return OR2(A::empty(p), B::empty(p));
    }
  };


  /*
    A rule consisting of a choice of rwo rules, e.g.
      rule ::= rule1 | rule2

    For the cases when the two branches have a compatible storage,
    passed as a CONTAINER, which must have constructors:
      CONTAINER(const A &a)
      CONTAINER(const B &b)
  */
  template<class PARSER, class CONTAINER, class A, class B>
  class OR2C: public CONTAINER
  {
  public:
    OR2C() = default;
    // Delete copying
    OR2C(const OR2C & rhs) = delete;
    OR2C & operator=(const OR2C & rhs) = delete;
    // Initializing from itself
    OR2C(OR2C &&rhs) = default;
    OR2C & operator=(OR2C &&rhs) = default;
    // Initializing from components
    OR2C(A &&a)
     :CONTAINER(std::move(a))
    { }
    OR2C(B &&b)
     :CONTAINER(std::move(b))
    { }
    OR2C(CONTAINER && rhs)
     :CONTAINER(std::move(rhs))
    { }
    static OR2C empty(const PARSER &parser)
    {
      CONTAINER tmp(CONTAINER::empty(parser));
      DBUG_ASSERT((bool) tmp);
      return tmp;
    }

    OR2C & operator=(A &&rhs)
    {
      CONTAINER::operator=(std::move(rhs));
      return *this;
    }
    OR2C & operator=(B &&rhs)
    {
      CONTAINER::operator=(std::move(rhs));
      return *this;
    }
    OR2C(PARSER *p)
     :CONTAINER(A(p))
    {
      if (CONTAINER::operator bool() ||
          CONTAINER::operator=(B(p)))
        return;
      DBUG_ASSERT(!CONTAINER::operator bool());
    }
    using Opt= OPT<PARSER, OR2C<PARSER, CONTAINER, A, B>>;
  };


  /*
    A rule consisting of a choice of three rules:
      rule ::= rule1 | rule2 | rule3

    For the case when the three branches have incompatible storage
  */
  template<class PARSER, class A, class B, class C>
  class OR3: public A, public B, public C
  {
  public:
    OR3() = default;
    // Delete copying
    OR3(const OR3 & rhs) = delete;
    OR3 & operator=(const OR3 & rhs) = delete;
    // Initializing from itself
    OR3(OR3 &&rhs) = default;
    OR3 & operator=(OR3 &&rhs) = default;
    // Initializing from components
    OR3(A &&a, B &&b, C &&c)
     :A(std::move(a)), B(std::move(b)), C(std::move(c))
    { }

    OR3(PARSER *p)
     :A(p),
      B(A::operator bool() ? B() : B(p)),
      C(A::operator bool() || B::operator bool() ? C() : C(p))
    {
      DBUG_ASSERT(!operator bool() || !p->is_error());
    }
    explicit operator bool() const
    {
      return A::operator bool() || B::operator bool() || C::operator bool();
    }
    static OR3 empty(const PARSER &p)
    {
      return OR3(A::empty(p), B::empty(p), C::empty(p));
    }
  };

  /*
    A rule consisting of a choice of three rules, e.g.
      rule ::= rule1 | rule2 | rule3

    For the cases when the three branches have a compatible storage,
    passed as a CONTAINER, which must have constructors:
      CONTAINER(const A &a)
      CONTAINER(const B &b)
      CONTAINER(const C &c)
  */
  template<class PARSER, class CONTAINER, class A, class B, class C>
  class OR3C: public CONTAINER
  {
  public:
    OR3C() = default;
    // Delete copying
    OR3C(const OR3C & rhs) = delete;
    OR3C & operator=(const OR3C & rhs) = delete;
    // Initializing from itself
    OR3C(OR3C &&rhs) = default;
    OR3C & operator=(OR3C &&rhs) = default;
    // Initializing from components
    OR3C(CONTAINER && rhs)
     :CONTAINER(std::move(rhs))
    { }
    static OR3C empty(const PARSER &parser)
    {
      return CONTAINER::empty(parser);
    }

    OR3C(A &&a)
     :CONTAINER(std::move(a))
    { }
    OR3C(B &&b)
     :CONTAINER(std::move(b))
    { }
    OR3C(C &&c)
     :CONTAINER(std::move(c))
    { }

    OR3C & operator=(A &&rhs)
    {
      CONTAINER::operator=(std::move(rhs));
      return *this;
    }
    OR3C & operator=(B &&rhs)
    {
      CONTAINER::operator=(std::move(rhs));
      return *this;
    }
    OR3C & operator=(C &&rhs)
    {
      CONTAINER::operator=(std::move(rhs));
      return *this;
    }

    OR3C(PARSER *p)
     :CONTAINER(A(p))
    {
      if (CONTAINER::operator bool() ||
          CONTAINER::operator=(B(p)) ||
          CONTAINER::operator=(C(p)))
        return;
      DBUG_ASSERT(!CONTAINER::operator bool());
    }
    using Opt= OPT<PARSER, OR3C<PARSER, CONTAINER, A, B, C>>;
  };


  /*
     A rule consisting of a choice of four rules:
        rule ::= rule1 | rule2 | rule3 | rule4
     For the case when the four branches have incompatible storage
  */
  template<class PARSER, class A, class B, class C, class D>
  class OR4: public A, public B, public C, public D
  {
  public:
    OR4() = default;
    // Delete copying
    OR4(const OR4 & rhs) = delete;
    OR4 & operator=(const OR4 & rhs) = delete;
    // Initializing from itself
    OR4(OR4 &&rhs) = default;
    OR4 & operator=(OR4 &&rhs) = default;

    OR4(PARSER *p)
     :A(p),
      B(A::operator bool() ? B() : B(p)),
      C(A::operator bool() || B::operator bool() ? C() : C(p)),
      D(A::operator bool() || B::operator bool() || C::operator bool() ?
          D() : D(p))
    {
      DBUG_ASSERT(!operator bool() || !p->is_error());
    }
    explicit operator bool() const
    {
      return A::operator bool() || B::operator bool() || C::operator bool() ||
             D::operator bool();
    }
  };


  /*
    A rule consisting of a choice of four rules, e.g.
      rule ::= rule1 | rule2 | rule3 | rule4

    For the cases when the three branches have a compatible storage,
    passed as a CONTAINER, which must have constructors:
      CONTAINER(const A && a)
      CONTAINER(const B && b)
      CONTAINER(const C && c)
      CONTAINER(const D && d)
  */
  template<class PARSER, class CONTAINER, class A, class B, class C, class D>
  class OR4C: public CONTAINER
  {
  public:
    OR4C() = default;
    // Delete copying
    OR4C(const OR4C & rhs) = delete;
    OR4C & operator=(const OR4C & rhs) = delete;
    // Initializing from itself
    OR4C(OR4C && rhs) = default;
    OR4C & operator=(OR4C && rhs) = default;
    // Initializing from components
    OR4C(CONTAINER && rhs) :CONTAINER(std::move(rhs)) { }
    OR4C(A && a)           :CONTAINER(std::move(a))   { }
    OR4C(B && b)           :CONTAINER(std::move(b))   { }
    OR4C(C && c)           :CONTAINER(std::move(c))   { }
    OR4C(D && d)           :CONTAINER(std::move(d))   { }

    // Initializing from its components
    OR4C & operator=(CONTAINER && rhs)
    {
      CONTAINER::operator=(std::move(rhs));
      return *this;
    }
    OR4C & operator=(A && rhs)
    {
      CONTAINER::operator=(std::move(rhs));
      return *this;
    }
    OR4C & operator=(B && rhs)
    {
      CONTAINER::operator=(std::move(rhs));
      return *this;
    }
    OR4C & operator=(C && rhs)
    {
      CONTAINER::operator=(std::move(rhs));
      return *this;
    }
    OR4C & operator=(D && rhs)
    {
      CONTAINER::operator=(std::move(rhs));
      return *this;
    }

    OR4C(PARSER *p)
     :CONTAINER(A(p))
    {
      if (CONTAINER::operator bool() ||
          CONTAINER::operator=(B(p)) ||
          CONTAINER::operator=(C(p)) ||
          CONTAINER::operator=(D(p)))
        return;
      DBUG_ASSERT(!CONTAINER::operator bool());
    }

    using Opt= OPT<PARSER, OR4C<PARSER, CONTAINER, A, B, C, D>>;

  };


  /*
    A rule consisting of a choice of four rules, e.g.
      rule ::= rule1 | rule2 | rule3 | rule4 | rule5

    For the cases when the three branches have a compatible storage,
    passed as a CONTAINER, which must have constructors:
      CONTAINER(const A && a)
      CONTAINER(const B && b)
      CONTAINER(const C && c)
      CONTAINER(const D && d)
      CONTAINER(const E && e)
  */
  template<class PARSER, class CONTAINER,
           class A, class B, class C, class D, class E>
  class OR5C: public CONTAINER
  {
  public:
    OR5C() = default;
    // Delete copying
    OR5C(const OR5C & rhs) = delete;
    OR5C & operator=(const OR5C & rhs) = delete;
    // Initializing from itself
    OR5C(OR5C && rhs) = default;
    OR5C & operator=(OR5C && rhs) = default;
    // Initializing from its components
    OR5C(CONTAINER && rhs) :CONTAINER(std::move(rhs)) { }
    OR5C & operator=(CONTAINER && rhs)
    {
      CONTAINER::operator=(std::move(rhs));
      return *this;
    }
    static OR5C empty(const PARSER &parser)
    {
      return CONTAINER::empty(parser);
    }
    static OR5C empty()
    {
      return CONTAINER::empty();
    }

    OR5C(A && a)      :CONTAINER(std::move(a))   { }
    OR5C(B && b)      :CONTAINER(std::move(b))   { }
    OR5C(C && c)      :CONTAINER(std::move(c))   { }
    OR5C(D && d)      :CONTAINER(std::move(d))   { }
    OR5C(E && e)      :CONTAINER(std::move(e))   { }

    OR5C & operator=(A && rhs)
    {
      CONTAINER::operator=(std::move(rhs));
      return *this;
    }
    OR5C & operator=(B && rhs)
    {
      CONTAINER::operator=(std::move(rhs));
      return *this;
    }
    OR5C & operator=(C && rhs)
    {
      CONTAINER::operator=(std::move(rhs));
      return *this;
    }
    OR5C & operator=(D && rhs)
    {
      CONTAINER::operator=(std::move(rhs));
      return *this;
    }
    OR5C & operator=(E && rhs)
    {
      CONTAINER::operator=(std::move(rhs));
      return *this;
    }

    OR5C(PARSER *p)
     :CONTAINER(A(p))
    {
      if (CONTAINER::operator bool() ||
          CONTAINER::operator=(B(p)) ||
          CONTAINER::operator=(C(p)) ||
          CONTAINER::operator=(D(p)) ||
          CONTAINER::operator=(E(p)))
        return;
      DBUG_ASSERT(!CONTAINER::operator bool());
    }

    using Opt= OPT<PARSER, OR5C<PARSER, CONTAINER, A, B, C, D, E>>;
  };


  /*
     A rule consisting of a choice of seven rules:
        rule ::= rule1 | rule2 | rule3 | rule4 | rule5 | rule6 | rule7
  */
  template<class PARSER, class A, class B, class C, class D, class E, class F,
           class G>
  class OR7: public A, public B, public C, public D, public E, public F,
      public G
  {
  public:
    OR7() = default;
    // Delete copying
    OR7(const OR7 & rhs) = delete;
    OR7 & operator=(const OR7 & rhs) = delete;
    // Initializing from itself
    OR7(OR7 &&rhs) = default;
    OR7 & operator=(OR7 &&rhs) = default;
    // Other methods
    OR7(PARSER *p)
     :A(p),
      B(A::operator bool() ? B() : B(p)),
      C(A::operator bool() || B::operator bool() ? C() : C(p)),
      D(A::operator bool() || B::operator bool() || C::operator bool() ?
          D() : D(p)),
      E(A::operator bool() || B::operator bool() || C::operator bool() ||
        D::operator bool() ? E() : E(p)),
      F(A::operator bool() || B::operator bool() || C::operator bool() ||
        D::operator bool() || E::operator bool() ? F() : F(p)),
      G(A::operator bool() || B::operator bool() || C::operator bool() ||
        D::operator bool() || E::operator bool() || F::operator bool() ?
          G() : G(p))
    {
      DBUG_ASSERT(!operator bool() || !p->is_error());
    }
    explicit operator bool() const
    {
      return A::operator bool() || B::operator bool() || C::operator bool() ||
             D::operator bool() || E::operator bool() || F::operator bool() ||
             G::operator bool();
    }
  };


  /*
    A list with at least MIN_COUNT elements (typlically 0 or 1),
    with or without a token separator between elements:

      list ::= element [ {, element }... ]       // with a separator
      list ::= element [    element  ... ]       // without a separator

    Pass the null-token special purpose ID in SEP for a non-separated list,
    or a real token ID for a separated list.

    If MIN_COUNT is 0, then the list becomes optional,
    which corresponds to the following grammar:

      list ::= [ element [ {, element }... ] ]   // with a separator
      list ::= [ element [    element  ... ] ]   // without a separator

    Template parameters:
    - PARSER         - The main parser class
    - LIST_CONTAINER - The class where the list parsed data is accumulated to
    - ELEMENT_PARSER - The element parser
    - SEP            - The ID of the separator token between elements.
                       If the ID is eqoal to null_token().id(),
                       then the list is not separated. See above.
    - MIN_COUNT      - The mininum number of elements. Usually 1.
                       0 means that the list is optional:  [ list ]
  */
  template<class PARSER,
           class LIST_CONTAINER, class ELEMENT_PARSER,
           typename PARSER::TokenID SEP, size_t MIN_COUNT>
  class LIST: public LIST_CONTAINER
  {
  protected:
    bool m_error;
  public:
    LIST()
     :m_error(true)
    { }
    // Delete copying
    LIST(const LIST & rhs) = delete;
    LIST & operator=(const LIST & rhs) = delete;
    // Initializing from its components
    /*
      This constructor is needed to initialize LIST from LIST_CONTAINER::empty()
    */
    LIST(LIST_CONTAINER &&rhs)
     :LIST_CONTAINER(std::move(rhs)),
      m_error(false)
    { }
    // Initializing from itself
    LIST(LIST &&rhs) = default;
    LIST & operator=(LIST &&rhs) = default;
    static LIST empty(const PARSER &parser)
    {
      return LIST(LIST_CONTAINER::empty(parser));
    }
    LIST(PARSER *p)
     :m_error(true)
    {
      // Determine if the caller wants a separated or a non-separated list
      const bool separated= SEP != PARSER::null_token().id();
      for ( ; ; )
      {
        ELEMENT_PARSER elem(p);
        if (!elem)
        {
          if (LIST_CONTAINER::count() == 0 || !separated)
          {
            /*
              Could not parse an element:
              1. the very first element in an optional list:
                 [ ELEM [,ELEM]...]
              2. or non-first element in a non-separated list:
                 ELEM [ELEM...]
              This state is OK, it's not a parse error, unless
              an error happened when parsing an ELEM subrule:
            */
            m_error= p->is_error();
            DBUG_ASSERT(!m_error || !operator bool());
#ifdef SIMPLE_PARSER_V2
            if (!p->is_error())
            {
              if (LIST_CONTAINER::count() == 0)
              {
                /*
                  This is the case #1 described above.
                  LIST_CONTAINER is currently in a "non parsed" state,
                  its operator bool() would return false.
                  Initialize LIST_CONTAINER to its "empty" value to make
                  operator bool() return true, to make the caller aware
                  that the list was parsed, just it was empty.
                */
                LIST_CONTAINER::operator=(empty(*p));
              }
            }
#endif
            return;
          }
          // Could not get the next element after the separator
          p->set_syntax_error();
          m_error= true;
          DBUG_ASSERT(!operator bool());
          return;
        }
        if (LIST_CONTAINER::add(p, std::move(elem)))
        {
          p->set_fatal_error();
          m_error= true;
          DBUG_ASSERT(!operator bool());
          return;
        }
        if (separated)
        {
          if (!p->token(SEP))
          {
            m_error= false;
            DBUG_ASSERT(operator bool());
            return;
          }
        }
      }
    }
    explicit operator bool() const
    {
      return !m_error && LIST_CONTAINER::count() >= MIN_COUNT;
    }
    // A parser for an optional list
    using Opt= LIST<PARSER, LIST_CONTAINER,
                    ELEMENT_PARSER, SEP, 0/*no elements is OK*/>;
  };

};

#endif // SIMPLE_PARSER_H
