Quinoa all test code coverage report
Current view: top level - Control - CommonGrammar.hpp (source / functions) Hit Total Coverage
Commit: -128-NOTFOUND Lines: 20 49 40.8 %
Date: 2024-11-22 08:51:48 Functions: 24 97 24.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 3 86 3.5 %

           Branch data     Line data    Source code
       1                 :            : // *****************************************************************************
       2                 :            : /*!
       3                 :            :   \file      src/Control/CommonGrammar.hpp
       4                 :            :   \copyright 2012-2015 J. Bakosi,
       5                 :            :              2016-2018 Los Alamos National Security, LLC.,
       6                 :            :              2019-2021 Triad National Security, LLC.
       7                 :            :              All rights reserved. See the LICENSE file for details.
       8                 :            :   \brief     Generic, low-level grammar, re-used by specific grammars
       9                 :            :   \details   Generic, low-level grammar. We use the Parsing Expression Grammar
      10                 :            :     Template Library (PEGTL) to create the grammar and the associated parser.
      11                 :            : */
      12                 :            : // *****************************************************************************
      13                 :            : #ifndef CommonGrammar_h
      14                 :            : #define CommonGrammar_h
      15                 :            : 
      16                 :            : #include <type_traits>
      17                 :            : #include <sstream>
      18                 :            : 
      19                 :            : #include <brigand/algorithms/for_each.hpp>
      20                 :            : #include <brigand/functions/logical/or.hpp>
      21                 :            : #include <brigand/sequences/has_key.hpp>
      22                 :            : 
      23                 :            : #include "If.hpp"
      24                 :            : #include "Exception.hpp"
      25                 :            : #include "Tags.hpp"
      26                 :            : #include "StatCtr.hpp"
      27                 :            : #include "Options/TxtFloatFormat.hpp"
      28                 :            : #include "Options/Error.hpp"
      29                 :            : 
      30                 :            : namespace tk {
      31                 :            : //! Toolkit general purpose grammar definition
      32                 :            : namespace grm {
      33                 :            : 
      34                 :            :   using namespace tao;
      35                 :            : 
      36                 :            :   using ncomp_t = kw::ncomp::info::expect::type;
      37                 :            : 
      38                 :            :   //! Parser's printer: this should be defined once per library in global-scope
      39                 :            :   //! (still in namespace, of course) by a parser. It is defined in
      40                 :            :   //! Control/[executable]/CmdLine/Parser.C, since every executable has at least
      41                 :            :   //! a command line parser.
      42                 :            :   extern Print g_print;
      43                 :            : 
      44                 :            :   // Common auxiliary functions (reused by multiple grammars)
      45                 :            : 
      46                 :            :   //! C-style enum indicating warning or error (used as template argument)
      47                 :            :   enum MsgType { ERROR=0, WARNING };
      48                 :            : 
      49                 :            :   //! Parser error types
      50                 :            :   enum class MsgKey : uint8_t {
      51                 :            :     KEYWORD,            //!< Unknown keyword
      52                 :            :     MOMENT,             //!< Unknown Term in a Moment
      53                 :            :     QUOTED,             //!< String must be double-quoted
      54                 :            :     LIST,               //!< Unknown value in list
      55                 :            :     ALIAS,              //!< Alias keyword too long
      56                 :            :     MISSING,            //!< Required field missing
      57                 :            :     PREMATURE,          //!< Premature end of line
      58                 :            :     UNSUPPORTED,        //!< Option not supported
      59                 :            :     NOOPTION,           //!< Option does not exist
      60                 :            :     NOINIT,             //!< No (or too many) initialization policy selected
      61                 :            :     NOPROBLEM,          //!< No test problem type selected
      62                 :            :     NOCOEFF,            //!< No coefficients policy selected
      63                 :            :     NOTSELECTED,        //!< Option not selected upstream
      64                 :            :     NOSOLVE,            //!< Dependent variable to solve for has not been spec'd
      65                 :            :     NOTALPHA,           //!< Variable must be alphanumeric
      66                 :            :     POINTEXISTS,        //!< Point identifier already defined
      67                 :            :     BADPRECISION,       //!< Floating point precision specification incorrect
      68                 :            :     BOUNDS,             //!< Specified value out of bounds
      69                 :            :     PRECISIONBOUNDS,    //!< Floating point precision spec out of bounds
      70                 :            :     UNFINISHED,         //!< Unfinished block
      71                 :            :     CHARMARG,           //!< Argument inteded for the Charm++ runtime system
      72                 :            :     OPTIONAL };         //!< Message key used to indicate of something optional
      73                 :            : 
      74                 :            :   //! Associate parser errors to error messages
      75                 :            :   static const std::map< MsgKey, std::string > message{
      76                 :            :     { MsgKey::KEYWORD, "Unknown keyword or keyword unrecognized in this "
      77                 :            :       "block." },
      78                 :            :     { MsgKey::MOMENT, "Unknown term in moment." },
      79                 :            :     { MsgKey::QUOTED, "Must be double-quoted." },
      80                 :            :     { MsgKey::LIST, "Unknown value in list." },
      81                 :            :     { MsgKey::ALIAS, "Alias keyword too long. Use either a full-length keyword "
      82                 :            :       "with double-hyphens, e.g., --keyword, or its alias, a single character, "
      83                 :            :       "with a single hyphen, e.g., -k." },
      84                 :            :     { MsgKey::MISSING, "Required field missing." },
      85                 :            :     { MsgKey::PREMATURE, "Premature end of line." },
      86                 :            :     { MsgKey::UNSUPPORTED, "Option not supported." },
      87                 :            :     { MsgKey::NOOPTION, "Option does not exist." },
      88                 :            :     { MsgKey::NOTSELECTED, "Option is not among the selected ones. The keyword "
      89                 :            :       "here is appropriate, but in order to use this keyword in this context, "
      90                 :            :       "the option must be selected upstream." },
      91                 :            :     { MsgKey::NOTALPHA, "Variable not alphanumeric." },
      92                 :            :     { MsgKey::NOSOLVE, "Dependent variable to solve for not specified within "
      93                 :            :       "the block preceding this position. This is mandatory for the preceding "
      94                 :            :       "block. Use the keyword 'solve' to specify the type of the dependent "
      95                 :            :       "variable to solve for." },
      96                 :            :     { MsgKey::NOINIT, "No (or too many) initialization policy (or policies) "
      97                 :            :       "has been specified within the block preceding this position. An "
      98                 :            :       "initialization policy (and only one) is mandatory for the preceding "
      99                 :            :       "block. Use the keyword 'init' to specify an initialization policy." },
     100                 :            :     { MsgKey::NOPROBLEM, "No test problem has been specified within the "
     101                 :            :       "block preceding this position. This is mandatory for the preceding "
     102                 :            :       "block. Use the keyword 'problem' to specify a test problem." },
     103                 :            :     { MsgKey::NOCOEFF, "No coefficients policy has been specified within the "
     104                 :            :       "block preceding this position. This is mandatory for the preceding "
     105                 :            :       "block. Use the keyword 'coeff' to specify an coefficients policy." },
     106                 :            :     { MsgKey::POINTEXISTS, "Point already exists. Point identifiers must be "
     107                 :            :       "unique."},
     108                 :            :     { MsgKey::BADPRECISION, "Precision specification invalid. It should be a "
     109                 :            :       "positive integer or the word \'max\', selecting the maximum number of "
     110                 :            :       "digits for the underyling floating point type."},
     111                 :            :     { MsgKey::BOUNDS, "Specified value out of bounds. For the bounds on a "
     112                 :            :       "keyword, run '<executable> -H <keyword>'."},
     113                 :            :     { MsgKey::PRECISIONBOUNDS, "Precision specification out of bounds. It "
     114                 :            :       "should be a positive integer between 1 and the maximum number of digits "
     115                 :            :       "for the underyling floating point type on the machine. (Set \'max\' for "
     116                 :            :       "the maximum.)"},
     117                 :            :     { MsgKey::UNFINISHED, "Block started but not finished by the 'end' "
     118                 :            :       "keyword." },
     119                 :            :     { MsgKey::CHARMARG, "Arguments starting with '+' are assumed to be inteded "
     120                 :            :       "for the Charm++ runtime system. Did you forget to prefix the command "
     121                 :            :       "line with charmrun? If this warning persists even after running with "
     122                 :            :       "charmrun, then Charm++ does not understand it either. See the Charm++ "
     123                 :            :       "manual at http://charm.cs.illinois.edu/manuals/html/charm++/"
     124                 :            :       "manual.html." },
     125                 :            :     { MsgKey::OPTIONAL, "This is not really an error message and thus it "
     126                 :            :       "should not be used as one. But its key can be used to indicate "
     127                 :            :       "something optional (which is not an error), which in some situations is "
     128                 :            :       "not optional (which is an error)." }
     129                 :            :   };
     130                 :            : 
     131                 :            :   //! Parser error and warning message handler.
     132                 :            :   //! \details This function is used to associated and dispatch an error or a
     133                 :            :   //!   warning during parsing. After finding the error message corresponding to
     134                 :            :   //!   a key, it pushes back the message to a std::vector of std::string, which
     135                 :            :   //!   then will be diagnosed later by tk::FileParser::diagnostics. The
     136                 :            :   //!   template arguments define (1) the grammar stack (Stack, a tagged tuple)
     137                 :            :   //!   to operate on, (2) the message type (error or warning), and (3) the
     138                 :            :   //!   message key used to look up the error message associated with the key.
     139                 :            :   //! \param[in,out] stack Grammar stack (a tagged tuple) to operate on
     140                 :            :   //! \param[in] in Last parsed PEGTL input token (can be empty, depending on
     141                 :            :   //!   what context this function gets called.
     142                 :            :   template< class Stack, MsgType type, MsgKey key, class Input >
     143                 :          0 :   static void Message( Stack& stack, const Input& in ) {
     144         [ -  - ]:          0 :     const auto& msg = message.find(key);
     145         [ -  - ]:          0 :     if (msg != message.end()) {
     146         [ -  - ]:          0 :       std::stringstream ss;
     147         [ -  - ]:          0 :       const std::string typestr( type == MsgType::ERROR ? "Error" : "Warning" );
     148         [ -  - ]:          0 :       auto pos = in.position();
     149         [ -  - ]:          0 :       if (!in.empty()) {
     150 [ -  - ][ -  - ]:          0 :         ss << typestr << " while parsing '" << in.string() << "' at "
         [ -  - ][ -  - ]
                 [ -  - ]
     151 [ -  - ][ -  - ]:          0 :            << pos.line << ',' << pos.byte_in_line << ". " << msg->second;
         [ -  - ][ -  - ]
                 [ -  - ]
     152                 :            :       } else {
     153 [ -  - ][ -  - ]:          0 :         ss << typestr << " while parsing at " << pos.line << ','
         [ -  - ][ -  - ]
     154 [ -  - ][ -  - ]:          0 :            << pos.byte_in_line << ". " << msg->second;
                 [ -  - ]
     155                 :            :       }
     156 [ -  - ][ -  - ]:          0 :       stack.template get< tag::error >().push_back( ss.str() );
     157                 :            :     } else {
     158 [ -  - ][ -  - ]:          0 :       stack.template get< tag::error >().push_back(
         [ -  - ][ -  - ]
     159                 :            :         std::string("Unknown parser ") +
     160                 :            :         (type == MsgType::ERROR ? "error" : "warning" ) +
     161                 :            :         " with no location information." );
     162                 :            :     }
     163                 :          0 :   }
     164                 :            : 
     165                 :            :   // Common PEGTL actions (PEGTL actions reused by multiple grammars)
     166                 :            : 
     167                 :            :   //! PEGTL action base: do nothing by default
     168                 :            :   //! \details This base is specialized to different actions duing parsing.
     169                 :            :   template< typename Rule >
     170                 :            :   struct action : pegtl::nothing< Rule > {};
     171                 :            : 
     172                 :            :   //! Helper for calling action::apply for multiple actions
     173                 :            :   template< typename... As >
     174                 :            :   struct call {
     175                 :            :     template< typename Input, typename State >
     176                 :        502 :     static void apply( const Input& in, State& state ) {
     177                 :            :         using swallow = bool[];
     178                 :        502 :         (void)swallow{ ( action< As >::apply( in, state ), true )..., true };
     179                 :        502 :      }
     180                 :            :   };
     181                 :            : 
     182                 :            :   //! Rule used to trigger action(s) for a rule
     183                 :            :   template< class rule, class... actions >
     184                 :            :   struct act : rule {};
     185                 :            : 
     186                 :            :   //! \details Specialization of action for act< rule, actions... >
     187                 :            :   template< class rule, class... actions >
     188                 :            :   struct action< act< rule, actions... > > : call< actions... > {};
     189                 :            : 
     190                 :            :   //! Rule used to trigger action
     191                 :            :   template< MsgType, MsgKey > struct msg : pegtl::success {};
     192                 :            :   //! Error message dispatch
     193                 :            :   //! \details This struct and its apply function are used to dispatch a message
     194                 :            :   //!   (e.g., error, waring) from the parser. It is simply an interface to
     195                 :            :   //!   Message. See This struct is practically used as a functor, i.e., a
     196                 :            :   //!   struct or class that defines the function call operator, but instead the
     197                 :            :   //!   function call operator, PEGTL uses the apply() member function for the
     198                 :            :   //!   actions. Thus this struct can be passed to, i.e., specialize a template,
     199                 :            :   //!   such as tk::grm::unknown, injecting in it the desired behavior.
     200                 :            :   template< MsgType type, MsgKey key >
     201                 :            :   struct action< msg< type, key > > {
     202                 :            :     template< typename Input, typename Stack >
     203                 :          0 :     static void apply( const Input& in, Stack& stack ) {
     204                 :          0 :       Message< Stack, type, key >( stack, in );
     205                 :          0 :     }
     206                 :            :   };
     207                 :            : 
     208                 :            :   //! Rule used to trigger action
     209                 :            :   template< typename tag, typename... tags > struct Store : pegtl::success {};
     210                 :            :   //! Put value in state at position given by tags with conversion
     211                 :            :   //! \details This struct and its apply function are used as a functor-like
     212                 :            :   //!    wrapper for calling the store member function of the underlying grammar
     213                 :            :   //!    stack, tk::Control::store.
     214                 :            :   template< typename tag, typename... tags >
     215                 :            :   struct action< Store< tag, tags... > > {
     216                 :            :     template< typename Input, typename Stack >
     217                 :        502 :     static void apply( const Input& in, Stack& stack ) {
     218         [ +  - ]:        502 :       if (!in.string().empty())
     219                 :        502 :         stack.template store< tag, tags... >( in.string() );
     220                 :            :       else
     221                 :          0 :         Message< Stack, ERROR, MsgKey::MISSING >( stack, in );
     222                 :        502 :     }
     223                 :            :   };
     224                 :            : 
     225                 :            :   //! Rule used to trigger action
     226                 :            :   template< typename... tags >
     227                 :            :   struct Invert_switch : pegtl::success {};
     228                 :            :   //! Invert bool in switch at position given by tags
     229                 :            :   //! \details This struct and its apply function are used as a functor-like
     230                 :            :   //!    wrapper for setting a boolean value to true in the underlying grammar
     231                 :            :   //!    stack via the member function tk::Control::set.
     232                 :            :   template< typename... tags >
     233                 :            :   struct action< Invert_switch< tags... > > {
     234                 :            :     template< typename Input, typename Stack >
     235                 :        442 :     static void apply( const Input&, Stack& stack ) {
     236                 :        442 :       stack.template get< tags... >() = !stack.template get< tags... >();
     237                 :        442 :     }
     238                 :            :   };
     239                 :            : 
     240                 :            :   //! Rule used to trigger action
     241                 :            :   struct helpkw : pegtl::success {};
     242                 :            :   //! \brief Find keyword among all keywords and if found, store the keyword
     243                 :            :   //!    and its info on which help was requested behind tag::helpkw in Stack
     244                 :            :   //! \details This struct and its apply function are used as a functor-like
     245                 :            :   //!    wrapper to search for a keyword in the pool of registered keywords
     246                 :            :   //!    recognized by a grammar and store the keyword and its info on which
     247                 :            :   //!    help was requested behind tag::helpkw. Note that this functor assumes
     248                 :            :   //!    a specific location for the std::maps of the command-line and control
     249                 :            :   //!    file keywords pools (behind tag::cmdinfo and tag::ctrinfo,
     250                 :            :   //!    respectively), and for the keyword and its info on which help was
     251                 :            :   //!    requested (behind tag::helpkw). This is the structure of CmdLine
     252                 :            :   //!    objects, thus this functor should be called from command line parsers.
     253                 :            :   template<>
     254                 :            :   struct action< helpkw > {
     255                 :            :     template< typename Input, typename Stack >
     256                 :          0 :     static void apply( const Input& in, Stack& stack ) {
     257                 :          0 :       const auto& cmdinfo = stack.template get< tag::cmdinfo >();
     258                 :          0 :       const auto& ctrinfo = stack.template get< tag::ctrinfo >();
     259 [ -  - ][ -  - ]:          0 :       auto it = cmdinfo.find( in.string() );
     260         [ -  - ]:          0 :       if (it != cmdinfo.end()) {
     261                 :            :         // store keyword and its info on which help was requested
     262 [ -  - ][ -  - ]:          0 :         stack.template get< tag::helpkw >() = { it->first, it->second, true };
     263                 :            :       } else {
     264 [ -  - ][ -  - ]:          0 :         it = ctrinfo.find( in.string() );
     265         [ -  - ]:          0 :         if (it != ctrinfo.end())
     266                 :            :           // store keyword and its info on which help was requested
     267 [ -  - ][ -  - ]:          0 :           stack.template get< tag::helpkw >() = { it->first, it->second, false };
     268                 :            :         else
     269         [ -  - ]:          0 :           Message< Stack, ERROR, MsgKey::KEYWORD >( stack, in );
     270                 :            :       }
     271                 :          0 :     }
     272                 :            :   };
     273                 :            : 
     274                 :            :   //! Rule used to trigger action
     275                 :            :   template< class keyword, typename tag, typename... tags >
     276                 :            :   struct check_lower_bound : pegtl::success {};
     277                 :            :   //! Check if value is larger than lower bound
     278                 :            :   template< class keyword, typename tag, typename... tags >
     279                 :            :   struct action< check_lower_bound< keyword, tag, tags... > > {
     280                 :            :     template< typename Input, typename Stack >
     281                 :         98 :     static void apply( const Input& in, Stack& stack ) {
     282                 :         98 :       auto lower = keyword::info::expect::lower;
     283                 :         98 :       auto val = stack.template get< tag, tags... >();
     284         [ -  + ]:         98 :       if (val < lower) Message< Stack, ERROR, MsgKey::BOUNDS >( stack, in );
     285                 :         98 :     }
     286                 :            :   };
     287                 :            : 
     288                 :            :   //! Rule used to trigger action
     289                 :            :   template< class keyword, typename tag, typename... tags >
     290                 :            :   struct check_upper_bound : pegtl::success {};
     291                 :            :   //! Check if value is lower than upper bound
     292                 :            :   template< class keyword, typename tag, typename... tags >
     293                 :            :   struct action< check_upper_bound< keyword, tag, tags... > > {
     294                 :            :     template< typename Input, typename Stack >
     295                 :         98 :     static void apply( const Input& in, Stack& stack ) {
     296                 :         98 :       auto upper = keyword::info::expect::upper;
     297                 :         98 :       auto val = stack.template get< tag, tags... >();
     298         [ -  + ]:         98 :       if (val > upper) Message< Stack, ERROR, MsgKey::BOUNDS >( stack, in );
     299                 :         98 :     }
     300                 :            :   };
     301                 :            : 
     302                 :            :   // Common grammar (grammar that is reused by multiple grammars)
     303                 :            : 
     304                 :            :   //! Read 'token' until 'erased' trimming, i.e., not consuming, 'erased'
     305                 :            :   template< class token, class erased >
     306                 :            :   struct trim :
     307                 :            :          pegtl::seq< token,
     308                 :            :                      pegtl::sor<
     309                 :            :                        pegtl::until< pegtl::at< erased > >,
     310                 :            :                        msg< ERROR, MsgKey::PREMATURE > > > {};
     311                 :            : 
     312                 :            :   //! Match unknown keyword and handle error
     313                 :            :   template< MsgType type, MsgKey key >
     314                 :            :   struct unknown :
     315                 :            :          pegtl::pad< pegtl::seq< trim< pegtl::any, pegtl::space >,
     316                 :            :                                  msg< type, key > >,
     317                 :            :                      pegtl::blank,
     318                 :            :                      pegtl::space > {};
     319                 :            : 
     320                 :            :   //! Match alias cmdline keyword
     321                 :            :   //! \details An alias command line keyword is prefixed by a single dash, '-'.
     322                 :            :   template< class keyword >
     323                 :            :   struct alias :
     324                 :            :          pegtl::seq<
     325                 :            :            pegtl::one< '-' >,
     326                 :            :            typename keyword::info::alias::type,
     327                 :            :            pegtl::sor< pegtl::space,
     328                 :            :                        msg< ERROR, MsgKey::ALIAS > >  > {};
     329                 :            : 
     330                 :            :   //! Match verbose cmdline keyword
     331                 :            :   //! \details A verbose command line keyword is prefixed by a double-dash,
     332                 :            :   //!   '--'.
     333                 :            :   template< class keyword >
     334                 :            :   struct verbose :
     335                 :            :          pegtl::seq< pegtl::string<'-','-'>,
     336                 :            :                      typename keyword::pegtl_string,
     337                 :            :                      pegtl::space > {};
     338                 :            : 
     339                 :            :   //! Read keyword 'token' padded by blank at left and space at right
     340                 :            :   template< class token >
     341                 :            :   struct readkw :
     342                 :            :          pegtl::pad< trim< token, pegtl::space >,
     343                 :            :                      pegtl::blank,
     344                 :            :                      pegtl::space > {};
     345                 :            : 
     346                 :            :   //! Read command line 'keyword' in verbose form, i.e., '--keyword'
     347                 :            :   //! \details This version is used if no alias is defined for the given keyword
     348                 :            :   template< class keyword, typename = void >
     349                 :            :   struct readcmd :
     350                 :            :          verbose< keyword > {};
     351                 :            : 
     352                 :            :   //! Read command line 'keyword' in either verbose or alias form
     353                 :            :   //! \details This version is used if an alias is defined for the given
     354                 :            :   //!   keyword, in which case either the verbose or the alias form of the
     355                 :            :   //!   keyword is matched, i.e., either '--keyword' or '-a', where 'a' is the
     356                 :            :   //!   single-character alias for the longer 'keyword'. This is a partial
     357                 :            :   //!   specialization of the simpler verbose-only readcmd, which attempts to
     358                 :            :   //!   find the typedef 'alias' in keyword::info. If it finds it, it uses this
     359                 :            :   //!   specialization. If it fails, it is [SFINAE]
     360                 :            :   //!   (http://en.cppreference.com/w/cpp/language/sfinae), and falls back to
     361                 :            :   //!   the verbose-only definition. Credit goes to David Rodriguez at
     362                 :            :   //!   stackoverflow.com. This allows not having to change this client-code to
     363                 :            :   //!   the keywords definitions: a keyword either defines an alias or not, and
     364                 :            :   //!   the grammar here will do the right thing: if there is an alias, it will
     365                 :            :   //!   build the grammar that optionally parses for it.
     366                 :            :   //! \see tk::if_
     367                 :            :   //! \see Control/Keyword.h and Control/Keywords.h
     368                 :            :   //! \see http://en.cppreference.com/w/cpp/language/sfinae
     369                 :            :   //! \see http://stackoverflow.com/a/11814074
     370                 :            :   template< class keyword >
     371                 :            :   struct readcmd< keyword,
     372                 :            :                   typename if_< false, typename keyword::info::alias >::type > :
     373                 :            :          pegtl::sor< verbose< keyword >, alias< keyword > > {};
     374                 :            : 
     375                 :            :   //! \brief Scan input padded by blank at left and space at right and if it
     376                 :            :   //!   matches 'keyword', apply 'actions'
     377                 :            :   //! \details As opposed to scan_until this rule, allows multiple actions
     378                 :            :   template< class keyword, class... actions >
     379                 :            :   struct scan :
     380                 :            :          pegtl::pad< act< trim< keyword, pegtl::space >, actions... >,
     381                 :            :                      pegtl::blank,
     382                 :            :                      pegtl::space > {};
     383                 :            : 
     384                 :            :   //! Parse a number: an optional sign followed by digits
     385                 :            :   struct number :
     386                 :            :          pegtl::seq< pegtl::opt< pegtl::sor< pegtl::one<'+'>,
     387                 :            :                                              pegtl::one<'-'> > >,
     388                 :            :                      pegtl::digit > {};
     389                 :            : 
     390                 :            :   //! \brief Process command line 'keyword' and call its 'insert' action if
     391                 :            :   //!   matches 'kw_type'
     392                 :            :   template< template< class > class use, class keyword, class insert,
     393                 :            :             class kw_type, class tag, class... tags >
     394                 :            :   struct process_cmd :
     395                 :            :          pegtl::if_must<
     396                 :            :            readcmd< use< keyword > >,
     397                 :            :            scan< pegtl::sor< kw_type, msg< ERROR, MsgKey::MISSING > >, insert >,
     398                 :            :            typename std::conditional<
     399                 :            :              tk::HasVar_expect_lower< typename keyword::info >::value,
     400                 :            :              check_lower_bound< keyword, tag, tags... >,
     401                 :            :              pegtl::success >::type,
     402                 :            :            typename std::conditional<
     403                 :            :              tk::HasVar_expect_upper< typename keyword::info >::value,
     404                 :            :              check_upper_bound< keyword, tag, tags... >,
     405                 :            :              pegtl::success >::type > {};
     406                 :            : 
     407                 :            :   //! Process command line switch 'keyword'
     408                 :            :   //! \details The value of a command line switch is a boolean, i.e., it can be
     409                 :            :   //!    either set or unset.
     410                 :            :   template< template< class > class use, class keyword, typename tag,
     411                 :            :             typename... tags >
     412                 :            :   struct process_cmd_switch :
     413                 :            :          pegtl::seq<readcmd< use<keyword> >, Invert_switch< tag, tags... >> {};
     414                 :            : 
     415                 :            :   //! Process but ignore Charm++'s charmrun arguments starting with '+'
     416                 :            :   struct charmarg :
     417                 :            :          pegtl::seq< pegtl::one<'+'>,
     418                 :            :                      unknown< WARNING, MsgKey::CHARMARG > > {};
     419                 :            : 
     420                 :            :   //! Generic string parser entry point: parse 'keywords' until end of string
     421                 :            :   template< typename keywords >
     422                 :            :   struct read_string :
     423                 :            :          pegtl::until< pegtl::eof,
     424                 :            :                        pegtl::sor<
     425                 :            :                          keywords,
     426                 :            :                          charmarg,
     427                 :            :                          unknown< ERROR, MsgKey::KEYWORD > > > {};
     428                 :            : 
     429                 :            :   //! \brief Ensure that a grammar only uses keywords from a pool of
     430                 :            :   //!   pre-defined keywords
     431                 :            :   //! \details In grammar definitions, every keyword should be wrapped around
     432                 :            :   //!   this use template, which conditionally inherits the keyword type its
     433                 :            :   //!   templated on (as defined in Control/Keywords.h) if the keyword is listed
     434                 :            :   //!   in any of the pools of keywords passed in as the required pool template
     435                 :            :   //!   argument and zero or more additional pools. If the keyword is not in any
     436                 :            :   //!   of the pools, a compiler error is generated, since the struct cannot
     437                 :            :   //!   inherit from base class 'char'. In that case, simply add the new keyword
     438                 :            :   //!   into one of the pools of keywords corresponding to the given grammar.
     439                 :            :   //!   The rationale behind this wrapper is to force the developer to maintain
     440                 :            :   //!   the keywords pool for a grammar. The pools are brigand::set and are
     441                 :            :   //!   used to provide help on command line arguments for a given executable.
     442                 :            :   //!   They allow compile-time iteration with brigand::for_each or
     443                 :            :   //!   generating a run-time std::map associating, e.g., keywords to their help
     444                 :            :   //!   strings.
     445                 :            :   //! \warning Note that an even more elegant solution to the problem this
     446                 :            :   //!   wrapper is intended to solve is to use a metaprogram that collects all
     447                 :            :   //!   occurrences of the keywords in a grammar. However, that does not seem to
     448                 :            :   //!   be possible without extensive macro-trickery. Instead, if all keywords
     449                 :            :   //!   in all grammar definitions are wrapped inside this use template (or one
     450                 :            :   //!   of its specializations), we make sure that only those keywords can be
     451                 :            :   //!   used by a grammar that are listed in the pool corresponding to a
     452                 :            :   //!   grammar. However, this is still only a partial solution, since listing
     453                 :            :   //!   more keywords in the pool than those used in the grammar is still
     454                 :            :   //!   possible, which would result in those keywords included in, e.g., the
     455                 :            :   //!   on-screen help generated even though some of the keywords may not be
     456                 :            :   //!   implemented by the given grammar. So please don't abuse and don't list
     457                 :            :   //!   keywords in the pool only if they are implemented in the grammar.
     458                 :            :   //! \see For example usage see the template typedef
     459                 :            :   //!   walker::cmd::use in Control/Walker/CmdLine/Grammar.h and its keywords
     460                 :            :   //!   pool, walker::ctr::CmdLine::keywords, in
     461                 :            :   //!   Control/Walker/CmdLine/CmdLine.h.
     462                 :            :   //! \see http://en.cppreference.com/w/cpp/types/conditional
     463                 :            :   //! TODO It still would be nice to generate a more developer-friendly
     464                 :            :   //!    compiler error if the keyword is not in the pool.
     465                 :            :   template< typename keyword, typename pool >
     466                 :            :   struct use :
     467                 :            :          std::conditional< brigand::or_<
     468                 :            :                              brigand::has_key< pool, keyword > >::value,
     469                 :            :                            keyword,
     470                 :            :                            char >::type {};
     471                 :            : 
     472                 :            : } // grm::
     473                 :            : } // tk::
     474                 :            : 
     475                 :            : #endif // CommonGrammar_h

Generated by: LCOV version 1.14