Quinoa unit test code coverage report
Current view: top level - Control - CommonGrammar.hpp (source / functions) Hit Total Coverage
Commit: Quinoa_v0.3-957-gb4f0efae0 Lines: 1 29 3.4 %
Date: 2021-11-09 12:13:43 Functions: 0 8 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 60 0.0 %

           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/PDFFile.hpp"
      28                 :            : #include "Options/PDFPolicy.hpp"
      29                 :            : #include "Options/PDFCentering.hpp"
      30                 :            : #include "Options/TxtFloatFormat.hpp"
      31                 :            : #include "Options/Error.hpp"
      32                 :            : 
      33                 :            : namespace tk {
      34                 :            : //! Toolkit general purpose grammar definition
      35                 :            : namespace grm {
      36                 :            : 
      37                 :            :   using namespace tao;
      38                 :            : 
      39                 :            :   using ncomp_t = kw::ncomp::info::expect::type;
      40                 :            : 
      41                 :            :   //! Parser's printer: this should be defined once per library in global-scope
      42                 :            :   //! (still in namespace, of course) by a parser. It is defined in
      43                 :            :   //! Control/[executable]/CmdLine/Parser.C, since every executable has at least
      44                 :            :   //! a command line parser.
      45                 :            :   extern Print g_print;
      46                 :            : 
      47                 :            :   // Common InputDeck state
      48                 :            : 
      49                 :            :   //! Out-of-struct storage of field ID for pushing terms for statistics
      50                 :            :   static ncomp_t field = 0;
      51                 :            :   //! \brief Parser-lifetime storage for dependent variables selected.
      52                 :            :   //! \details Used to track the dependent variable of differential equations
      53                 :            :   //!   (i.e., models) assigned during parsing. It needs to be case insensitive
      54                 :            :   //!   since we only care about whether the variable is selected or not and not
      55                 :            :   //!   whether it denotes a full variable (upper case) or a fluctuation (lower
      56                 :            :   //!   case). This is true for both inserting variables into the set as well as
      57                 :            :   //!   at matching terms of products in parsing requested statistics.
      58                 :            :   static std::set< char, tk::ctr::CaseInsensitiveCharLess > depvars;
      59                 :            :   //! \brief Parser-lifetime storage for PDF names
      60                 :            :   //! \details Used to track the names of PDFs registered so that parsing new
      61                 :            :   //!    ones can be required to be unique.
      62                 :            :   static std::set< std::string > pdfnames;
      63                 :            : 
      64                 :            :   // Common auxiliary functions (reused by multiple grammars)
      65                 :            : 
      66                 :            :   //! C-style enum indicating warning or error (used as template argument)
      67                 :            :   enum MsgType { ERROR=0, WARNING };
      68                 :            : 
      69                 :            :   //! Parser error types
      70                 :            :   enum class MsgKey : uint8_t {
      71                 :            :     KEYWORD,            //!< Unknown keyword
      72                 :            :     MOMENT,             //!< Unknown Term in a Moment
      73                 :            :     QUOTED,             //!< String must be double-quoted
      74                 :            :     LIST,               //!< Unknown value in list
      75                 :            :     ALIAS,              //!< Alias keyword too long
      76                 :            :     MISSING,            //!< Required field missing
      77                 :            :     PREMATURE,          //!< Premature end of line
      78                 :            :     UNSUPPORTED,        //!< Option not supported
      79                 :            :     NOOPTION,           //!< Option does not exist
      80                 :            :     NOINIT,             //!< No (or too many) initialization policy selected
      81                 :            :     NOPROBLEM,          //!< No test problem type selected
      82                 :            :     NOCOEFF,            //!< No coefficients policy selected
      83                 :            :     NOTSELECTED,        //!< Option not selected upstream
      84                 :            :     EXISTS,             //!< Variable already used
      85                 :            :     NODEPVAR,           //!< Dependent variable has not been specified
      86                 :            :     DEPVAR_AS_MESHREF,  //!< Depvar upstream of meshref has not been specified
      87                 :            :     LOC_NOMESHREF,      //!< Mesh location without reference mesh
      88                 :            :     ORI_NOMESHREF,      //!< Mesh orientation without reference mesh
      89                 :            :     MULTIMESH,          //!< If meshes are assigned, all solvers must have one
      90                 :            :     NOSOLVE,            //!< Dependent variable to solve for has not been spec'd
      91                 :            :     NOSUCHDEPVAR,       //!< Dependent variable has not been previously selected
      92                 :            :     NOSUCHCOMPONENT,    //!< No such scalar component
      93                 :            :     NOSUCHOUTVAR,       //!< Output variable label not acceptable
      94                 :            :     NOSUCHMULTIMATVAR,  //!< Variable not acceptable for multi-material output
      95                 :            :     POSITIVECOMPONENT,  //!< Scalar component must be positive
      96                 :            :     NOTALPHA,           //!< Variable must be alphanumeric
      97                 :            :     NOTERMS,            //!< Statistic need a variable
      98                 :            :     ODDSPIKES,          //!< Incomplete spikes block
      99                 :            :     HEIGHTSPIKES,       //!< Height-sum of spikes does not add up to unity
     100                 :            :     NODELTA,            //!< No icdelta...end block when initpolicy = jointdelta
     101                 :            :     NOBETA,             //!< No icbeta...end block when initpolicy = jointbeta
     102                 :            :     NOGAMMA,            //!< No icgamma...end block when initpolicy = jointgamma
     103                 :            :     NOMEAN,             //!< No mean when initpolicy = jointcorrgaussian
     104                 :            :     NOCOV,              //!< No cov when initpolicy = jointcorrgaussian
     105                 :            :     NOMKLRNG,           //!< No MKL RNG configured
     106                 :            :     WRONGBETAPDF,       //!< Wrong number of parameters for a beta pdf
     107                 :            :     WRONGGAMMAPDF,      //!< Wrong number of parameters for a gamma pdf
     108                 :            :     WRONGGAUSSIAN,      //!< Wrong number of parameters for a Gaussian PDF
     109                 :            :     WRONGDIRICHLET,     //!< Wrong number of parameters for a Dirichlet PDF
     110                 :            :     NEGATIVEPARAM,      //!< Negative parameter given configuring a PDF
     111                 :            :     NONCOMP,            //!< No number of components selected
     112                 :            :     LARGECOMP,          //!< Component index indexing out of max eq sys ncomp
     113                 :            :     BADRANGE,           //!< Incorrect time range configuration
     114                 :            :     NONMAT,             //!< No number of materials selected
     115                 :            :     NUMMAT,             //!< Incorrect number of materials selected
     116                 :            :     REPMATID,           //!< Repeating material id
     117                 :            :     ONEMATID,           //!< Material id not one-based
     118                 :            :     GAPMATID,           //!< Material id not contiguous
     119                 :            :     EOSGAMMA,           //!< Wrong number of EOS gamma parameters
     120                 :            :     EOSCV,              //!< Wrong number of EOS cv parameters
     121                 :            :     EOSPSTIFF,          //!< Wrong number of EOS pstiff parameters
     122                 :            :     NORNG,              //!< No RNG selected
     123                 :            :     NODT,               //!< No time-step-size policy selected
     124                 :            :     MULDT,              //!< Multiple time-step-size policies selected
     125                 :            :     NOSAMPLES,          //!< PDF need a variable
     126                 :            :     INVALIDSAMPLESPACE, //!< PDF sample space specification incorrect
     127                 :            :     MALFORMEDSAMPLE,    //!< PDF sample space variable specification incorrect
     128                 :            :     INVALIDBINSIZE,     //!< PDF sample space bin size specification incorrect
     129                 :            :     INVALIDEXTENT,      //!< PDF sample space extent specification incorrect
     130                 :            :     EXTENTLOWER,        //!< PDF sample space extents in non-increasing order
     131                 :            :     NOBINS,             //!< PDF sample space bin size required
     132                 :            :     ZEROBINSIZE,        //!< PDF sample space bin size incorrect
     133                 :            :     MAXSAMPLES,         //!< PDF sample space dimension too large
     134                 :            :     MAXBINSIZES,        //!< PDF sample space bin sizes too many
     135                 :            :     MAXEXTENTS,         //!< PDF sample space extent-pairs too many
     136                 :            :     BINSIZES,           //!< PDF sample space vars unequal to number of bins
     137                 :            :     PDF,                //!< PDF specification syntax error
     138                 :            :     PDFEXISTS,          //!< PDF identifier already defined
     139                 :            :     POINTEXISTS,        //!< Point identifier already defined
     140                 :            :     BADPRECISION,       //!< Floating point precision specification incorrect
     141                 :            :     BOUNDS,             //!< Specified value out of bounds
     142                 :            :     PRECISIONBOUNDS,    //!< Floating point precision spec out of bounds
     143                 :            :     UNFINISHED,         //!< Unfinished block
     144                 :            :     VORTICAL_UNFINISHED,//!< Vortical flow problem configuration unfinished
     145                 :            :     ENERGY_UNFINISHED,  //!< Nonlinear energy growth problem config unfinished
     146                 :            :     RT_UNFINISHED,      //!< Reyleigh-Taylor unstable configuration unfinished
     147                 :            :     BC_EMPTY,           //!< Empty boundary condition block
     148                 :            :     SYSFCTVAR,          //!< System-FCT variable index incorrect
     149                 :            :     BGICMISSING,        //!< Background IC unspecified
     150                 :            :     BGMATIDMISSING,     //!< Background material id unspecified
     151                 :            :     BOXMATIDMISSING,    //!< Box material id unspecified
     152                 :            :     BOXMATIDWRONG,      //!< Box material id incorrect
     153                 :            :     STAGBCWRONG,        //!< Stagnation BC incorrectly configured
     154                 :            :     SKIPBCWRONG,        //!< Skip BC incorrectly configured
     155                 :            :     SPONGEBCWRONG,      //!< Sponge BC incorrectly configured
     156                 :            :     NONDISJOINTBC,      //!< Different BC types assigned to the same side set
     157                 :            :     WRONGSIZE,          //!< Size of parameter vector incorrect
     158                 :            :     WRONGMESHMOTION,    //!< Error in mesh motion dimensions
     159                 :            :     STEADYALE,          //!< ALE + steady state not supported
     160                 :            :     INCOMPLETEUSERFN,   //!< Incomplete user-defined function
     161                 :            :     HYDROTIMESCALES,    //!< Missing required hydrotimescales vector
     162                 :            :     HYDROPRODUCTIONS,   //!< Missing required hydroproductions vector
     163                 :            :     POSITION_DEPVAR,    //!< Missing required position model dependent variable
     164                 :            :     VELOCITY_DEPVAR,    //!< Missing required velocity model dependent variable
     165                 :            :     DISSIPATION_DEPVAR, //!< Missing required dissipation model dependent var
     166                 :            :     MIXMASSFRACBETA_DEPVAR,//!< Missing required mass fraction model dependent var
     167                 :            :     POSITION_MISSING,   //!< Missing required position model
     168                 :            :     VELOCITY_MISSING,   //!< Missing required velocity model
     169                 :            :     DISSIPATION_MISSING,//!< Missing required dissipation model
     170                 :            :     MIXDIR_RHO,         //!< MixDirichlet parameter vector rho inconsistent
     171                 :            :     T0REFODD,           //!< AMR initref vector size is odd (must be even)
     172                 :            :     T0REFNOOP,          //!< AMR t<0 refinement will be no-op
     173                 :            :     DTREFNOOP,          //!< AMR t>0 refinement will be no-op
     174                 :            :     PREFTOL,            //!< p-refinement tolerance out of bounds
     175                 :            :     CHARMARG,           //!< Argument inteded for the Charm++ runtime system
     176                 :            :     OPTIONAL };         //!< Message key used to indicate of something optional
     177                 :            : 
     178                 :            :   //! Associate parser errors to error messages
     179                 :            :   static const std::map< MsgKey, std::string > message{
     180                 :            :     { MsgKey::KEYWORD, "Unknown keyword or keyword unrecognized in this "
     181                 :            :       "block." },
     182                 :            :     { MsgKey::MOMENT, "Unknown term in moment." },
     183                 :            :     { MsgKey::QUOTED, "Must be double-quoted." },
     184                 :            :     { MsgKey::LIST, "Unknown value in list." },
     185                 :            :     { MsgKey::ALIAS, "Alias keyword too long. Use either a full-length keyword "
     186                 :            :       "with double-hyphens, e.g., --keyword, or its alias, a single character, "
     187                 :            :       "with a single hyphen, e.g., -k." },
     188                 :            :     { MsgKey::MISSING, "Required field missing." },
     189                 :            :     { MsgKey::PREMATURE, "Premature end of line." },
     190                 :            :     { MsgKey::UNSUPPORTED, "Option not supported." },
     191                 :            :     { MsgKey::NOOPTION, "Option does not exist." },
     192                 :            :     { MsgKey::NOTSELECTED, "Option is not among the selected ones. The keyword "
     193                 :            :       "here is appropriate, but in order to use this keyword in this context, "
     194                 :            :       "the option must be selected upstream." },
     195                 :            :     { MsgKey::EXISTS, "Dependent variable already used." },
     196                 :            :     { MsgKey::NOSUCHDEPVAR, "Dependent variable not selected upstream in the "
     197                 :            :       "input file. To request an output variable, a statistic, configure a PDF "
     198                 :            :       "a involving this variable, use this variable as a coefficients policy "
     199                 :            :       "variable, use this variable as a refinement variable, or use a "
     200                 :            :       "dependent variable in any way, an equation must be specified upstream "
     201                 :            :       "in the control file assigning this variable to an equation to be "
     202                 :            :       "integrated using the depvar keyword." },
     203                 :            :     { MsgKey::NOSUCHCOMPONENT, "Scalar component, used in conjunction with "
     204                 :            :       "dependent variable, does not exist upstream in the input file. This "
     205                 :            :       "happens when referring to a scalar component of a multi-component "
     206                 :            :       "system of equations that has less than the number of total components "
     207                 :            :       "than the one specified. Note that numbering of the components starts "
     208                 :            :       "from 1 and their maximum value is the number specified by the 'ncomp' "
     209                 :            :       "keyword, inclusive, if applicable for the equation block the component "
     210                 :            :       "specification refers to. Note that there are equation system types for "
     211                 :            :       "which the number of components are not configurable with the 'ncomp' "
     212                 :            :       "keyword, instead their ncomp is assumed known, e.g., for compflow ncomp "
     213                 :            :       "= 5." },
     214                 :            :     { MsgKey::NOSUCHOUTVAR, "Scalar component label is not acceptable as a "
     215                 :            :       "request for an output variable. Did you mean it as upper case (as a "
     216                 :            :       "request for an instantaneous) quantity?" },
     217                 :            :     { MsgKey::NOSUCHMULTIMATVAR, "Scalar component label is not acceptable "
     218                 :            :       "requesting a multi-material output variable. Did you mean it as upper "
     219                 :            :       "case (as a request for an instantaneous) quantity?" },
     220                 :            :     { MsgKey::POSITIVECOMPONENT, "Scalar component must be positive." },
     221                 :            :     { MsgKey::NOTALPHA, "Variable not alphanumeric." },
     222                 :            :     { MsgKey::HEIGHTSPIKES, "The sum of all spike heights given in the "
     223                 :            :       "spike...end block does not add up to unity. A spike...end block "
     224                 :            :       "must contain an even number of real numbers, where every odd one is the "
     225                 :            :       "sample space position of a spike followed by the spike height "
     226                 :            :       "specifying the relative probability of the spike. Since the spike "
     227                 :            :       "heights are probabilities relative to unity, they must sum to one." },
     228                 :            :     { MsgKey::NODEPVAR, "Dependent variable not specified within the block "
     229                 :            :       "preceding this position. This is mandatory for the preceding block. Use "
     230                 :            :       "the keyword 'depvar' to specify the dependent variable." },
     231                 :            :     { MsgKey::DEPVAR_AS_MESHREF, "Error in the preceding solver-configuration "
     232                 :            :        "block. Dependent variable, attempted to be used as a mesh reference "
     233                 :            :        "variable (to couple to another solver) not specified in a solver "
     234                 :            :        "upstream. To be able to couple a solver to another one, a dependent "
     235                 :            :        "variable of a solver, defined upstream in the input file, can be "
     236                 :            :        "selected. This also means that the current depvar cannot be used as "
     237                 :            :        "the mesh reference variable." },
     238                 :            :     { MsgKey::LOC_NOMESHREF, "Location was configured without reference mesh. "
     239                 :            :        "This is insufficient: which mesh the location should be used with? "
     240                 :            :        "Either remove the location or add a reference mesh." },
     241                 :            :     { MsgKey::ORI_NOMESHREF, "Orientation was configured without reference "
     242                 :            :        "mesh. This is insufficient: which mesh the orientation should be used "
     243                 :            :        "with? Either remove the orientation or add a reference mesh." },
     244                 :            :     { MsgKey::MULTIMESH, "If a solver is assigned a mesh in the input/control "
     245                 :            :        "file, all solvers must have a mesh assigned. If no solver has a mesh "
     246                 :            :        "assigned, the (single) mesh must be specified on the command line." },
     247                 :            :     { MsgKey::NOSOLVE, "Dependent variable to solve for not specified within "
     248                 :            :       "the block preceding this position. This is mandatory for the preceding "
     249                 :            :       "block. Use the keyword 'solve' to specify the type of the dependent "
     250                 :            :       "variable to solve for." },
     251                 :            :     { MsgKey::NONCOMP, "The number of components has not been specified in the "
     252                 :            :       "block preceding this position. This is mandatory for the preceding "
     253                 :            :       "block. Use the keyword 'ncomp' to specify the number of components." },
     254                 :            :     { MsgKey::LARGECOMP, "The component index is too large and indexes out of "
     255                 :            :       "the total number of scalar components of the equation system "
     256                 :            :       "configured." },
     257                 :            :     { MsgKey::BADRANGE, "Incorrect output time range configuration. "
     258                 :            :       "Configuration for a time range must contain exactly 3 reals, "
     259                 :            :       "specifying mintime, maxtime, and dt, as exactly 3 reals in that order, "
     260                 :            :       "with maxtime > mintime and 0 < dt < maxtime-mintime." },
     261                 :            :     { MsgKey::NONMAT, "The number of materials has not been specified in the "
     262                 :            :       "block preceding this position. This is mandatory for the preceding "
     263                 :            :       "block. Use the keyword 'nmat' to specify the number of materials." },
     264                 :            :     { MsgKey::NUMMAT, "The total number of materials in all the material "
     265                 :            :       "blocks is not equal to the number of materials 'nmat' specified for "
     266                 :            :       "this system." },
     267                 :            :     { MsgKey::REPMATID, "Repeating material id specified in 'material ... end' "
     268                 :            :       "block. Material ids must be unique." },
     269                 :            :     { MsgKey::ONEMATID, "Material ids specified in 'material ... end' blocks "
     270                 :            :       "not one-based. Material ids must begin with one." },
     271                 :            :     { MsgKey::GAPMATID, "Material ids specified in 'material ... end' blocks "
     272                 :            :       "have a gap. Material ids must be contiguous." },
     273                 :            :     { MsgKey::EOSGAMMA, "Incorrect number of equation of state (EOS) 'gamma' "
     274                 :            :       "parameters configured in the preceding block's 'material ... end' "
     275                 :            :       "sub-block. The number of components between 'gamma ... end' is "
     276                 :            :       "incorrect, whose size must equal the number of material-ids set by "
     277                 :            :       "keyword 'id' in that 'material ... end' sub-block." },
     278                 :            :     { MsgKey::EOSCV, "Incorrect number of equation of state (EOS) 'cv' "
     279                 :            :       "parameters configured in the preceding block's 'material ... end' "
     280                 :            :       "sub-block. The number of components between 'cv... end' is "
     281                 :            :       "incorrect, whose size must equal the number of material-ids set by "
     282                 :            :       "keyword 'id' in that 'material ... end' sub-block." },
     283                 :            :     { MsgKey::EOSPSTIFF, "Incorrect number of equation of state (EOS) 'pstiff' "
     284                 :            :       "parameters configured in the preceding block's 'material ... end' "
     285                 :            :       "sub-block. The number of components between 'pstiff ... end' "
     286                 :            :       "is incorrect, whose size must equal the number of material-ids set by "
     287                 :            :       "keyword 'id' in that 'material ... end' sub-block." },
     288                 :            :     { MsgKey::NORNG, "The random number generator has not been specified in "
     289                 :            :       "the block preceding this position. This is mandatory for the preceding "
     290                 :            :       "block. Use the keyword 'rng' to specify the random number generator." },
     291                 :            :     { MsgKey::NODT, "No time step calculation policy has been selected in the "
     292                 :            :       "preceeding block. Use keyword 'dt' to set a constant or 'cfl' to set an "
     293                 :            :        "adaptive time step size calculation policy." },
     294                 :            :     { MsgKey::MULDT, "Multiple time step calculation policies has been "
     295                 :            :       "selected in the preceeding block. Use either keyword 'dt' to set a "
     296                 :            :       "constant or 'cfl' to set an adaptive time step size calculation policy. "
     297                 :            :       "Setting 'cfl' and 'dt' are mutually exclusive. If both 'cfl' and 'dt' "
     298                 :            :       "are set, 'dt' wins." },
     299                 :            :     { MsgKey::NOINIT, "No (or too many) initialization policy (or policies) "
     300                 :            :       "has been specified within the block preceding this position. An "
     301                 :            :       "initialization policy (and only one) is mandatory for the preceding "
     302                 :            :       "block. Use the keyword 'init' to specify an initialization policy." },
     303                 :            :     { MsgKey::NOPROBLEM, "No test problem has been specified within the "
     304                 :            :       "block preceding this position. This is mandatory for the preceding "
     305                 :            :       "block. Use the keyword 'problem' to specify a test problem." },
     306                 :            :     { MsgKey::NOCOEFF, "No coefficients policy has been specified within the "
     307                 :            :       "block preceding this position. This is mandatory for the preceding "
     308                 :            :       "block. Use the keyword 'coeff' to specify an coefficients policy." },
     309                 :            :     { MsgKey::NODELTA, "No icdelta...end block with at least a single "
     310                 :            :       "spike...end block has been specified within the block preceding this "
     311                 :            :       "position. This is mandatory for the preceding block if the joint delta "
     312                 :            :       "initpolicy is selected. Pick an initpolicy different than jointdelta "
     313                 :            :       "(using keyword 'init') or specify at least a single spike...end block "
     314                 :            :       "(within an icdelta...end block)." },
     315                 :            :     { MsgKey::NOBETA, "No beta...end block with at least a single "
     316                 :            :       "betapdf...end block has been specified within the block preceding this "
     317                 :            :       "position. This is mandatory for the preceding block if jointbeta "
     318                 :            :       "initpolicy is selected. Pick an initpolicy different than jointbeta "
     319                 :            :       "(using keyword 'init') or specify at least a single betapdf...end block "
     320                 :            :       "(within a icbeta...end block)." },
     321                 :            :     { MsgKey::NOGAMMA, "No gamma...end block with at least a single "
     322                 :            :       "gammapdf...end block has been specified within the block preceding this "
     323                 :            :       "position. This is mandatory for the preceding block if jointgamma "
     324                 :            :       "initpolicy is selected. Pick an initpolicy different than jointgamma "
     325                 :            :       "(using keyword 'init') or specify at least a single gammapdf...end block "
     326                 :            :       "(within a icgamma...end block)." },
     327                 :            :     { MsgKey::NOMEAN, "No means have been specified within icjointgaussian..."
     328                 :            :       "end block for jointcorrgaussian initialization policy." },
     329                 :            :     { MsgKey::NOCOV, "No covariance matrix has been specified within "
     330                 :            :       "icjointgaussian...end block for jointcorrgaussian initialization "
     331                 :            :       "policy." },
     332                 :            :     { MsgKey::NOMKLRNG, "No MKL random number generator has been configured "
     333                 :            :       "for the equation integrated. If the initialization policy is "
     334                 :            :       "configured to be as the joint correlated Gaussian, a RNG provided by "
     335                 :            :       "Intel's Math Kernel Library is required." },
     336                 :            :     { MsgKey::ODDSPIKES, "Incomplete spike...end block has been specified "
     337                 :            :       "within the  block preceding this position. A spike...end block "
     338                 :            :       "must contain an even number of real numbers, where every odd one is the "
     339                 :            :       "sample space position of a spike followed by the spike height "
     340                 :            :       "specifying the relative probability of the spike." },
     341                 :            :     { MsgKey::WRONGBETAPDF, "Wrong number of beta distribution parameters. A "
     342                 :            :       "beta distribution must be configured by exactly four real numbers in a "
     343                 :            :       "betapdf...end block." },
     344                 :            :     { MsgKey::WRONGGAMMAPDF, "Wrong number of gamma distribution parameters. A "
     345                 :            :       "gamma distribution must be configured by exactly two real numbers in a "
     346                 :            :       "gammapdf...end block." },
     347                 :            :     { MsgKey::WRONGGAUSSIAN, "Wrong number of Gaussian distribution "
     348                 :            :       "parameters. A Gaussian distribution must be configured by exactly 2 "
     349                 :            :       "real numbers in a gaussian...end block." },
     350                 :            :     { MsgKey::WRONGDIRICHLET, "Wrong number of Dirichlet distribution "
     351                 :            :       "parameters." },
     352                 :            :     { MsgKey::NEGATIVEPARAM, "Negative distribution parameter (e.g., variance, "
     353                 :            :       "shape, scale) specified configuring a probabililty distribution." },
     354                 :            :     { MsgKey::NOTERMS, "Statistic requires at least one variable." },
     355                 :            :     { MsgKey::NOSAMPLES, "PDF requires at least one sample space variable." },
     356                 :            :     { MsgKey::INVALIDSAMPLESPACE, "PDF sample space specification incorrect. A "
     357                 :            :       "non-empty list of sample space variables, must be followed by a "
     358                 :            :       "colon, followed by a non-empty list of bin sizes (reals numbers), e.g., "
     359                 :            :       "\"(x y : 0.1 0.2)\"" },
     360                 :            :     { MsgKey::MALFORMEDSAMPLE, "A PDF sample space variable must be a single "
     361                 :            :       "upper or lowercase letter optionally followed by an integer. "
     362                 :            :       "Multiple variables, specifying a multi-dimensional sample space, must "
     363                 :            :       "be separated by white spaces." },
     364                 :            :     { MsgKey::INVALIDBINSIZE, "PDF sample space bin size(s) specification "
     365                 :            :       "incorrect. A non-empty list of sample space variables, must be followed "
     366                 :            :       "by a colon, followed by a non-empty list of bin sizes (real numbers), "
     367                 :            :       "e.g., \"(x y : 0.1 0.2)\"" },
     368                 :            :     { MsgKey::INVALIDEXTENT, "PDF sample space extents specification "
     369                 :            :       "incorrect. The semi-colon following the list of bin sizes, must be "
     370                 :            :       "followed by a non-empty list of extents (real numbers), e.g., \"(x y : "
     371                 :            :       "0.1 0.2 ; 0.0 1.0 0.2 0.9)\". The number of real numbers representing "
     372                 :            :       "the sample space extents must be exactly twice the number of sample "
     373                 :            :       "space dimensions, i.e., in this 2D example 4 (2 pairs)." },
     374                 :            :     { MsgKey::EXTENTLOWER, "PDF sample space extents must be a pair of a "
     375                 :            :       "smaller and a larger numerical value, in that order." },
     376                 :            :     { MsgKey::NOBINS, "Need at least one sample space bin size, followed by a "
     377                 :            :       "colon, in a PDF specification." },
     378                 :            :     { MsgKey::ZEROBINSIZE, "Sample space bin size must be a real number and "
     379                 :            :       "greater than zero." },
     380                 :            :     { MsgKey::MAXSAMPLES, "The maximum number of sample space variables for a "
     381                 :            :       "joint PDF is 3." },
     382                 :            :     { MsgKey::MAXBINSIZES, "The maximum number of bins sizes for a joint PDF "
     383                 :            :       "is 3."},
     384                 :            :     { MsgKey::MAXEXTENTS, "The maximum number of optional sample space extents "
     385                 :            :       "for a joint PDF is 3 pairs."},
     386                 :            :     { MsgKey::BINSIZES, "The number of sample space variables for a PDF must "
     387                 :            :       "equal the number of bin sizes given." },
     388                 :            :     { MsgKey::PDF, "Syntax error while parsing PDF specification." },
     389                 :            :     { MsgKey::PDFEXISTS, "PDF already exists. PDF identifiers must be unique."},
     390                 :            :     { MsgKey::POINTEXISTS, "Point already exists. Point identifiers must be "
     391                 :            :       "unique."},
     392                 :            :     { MsgKey::BADPRECISION, "Precision specification invalid. It should be a "
     393                 :            :       "positive integer or the word \'max\', selecting the maximum number of "
     394                 :            :       "digits for the underyling floating point type."},
     395                 :            :     { MsgKey::BOUNDS, "Specified value out of bounds. For the bounds on a "
     396                 :            :       "keyword, run '<executable> -H <keyword>'."},
     397                 :            :     { MsgKey::PRECISIONBOUNDS, "Precision specification out of bounds. It "
     398                 :            :       "should be a positive integer between 1 and the maximum number of digits "
     399                 :            :       "for the underyling floating point type on the machine. (Set \'max\' for "
     400                 :            :       "the maximum.)"},
     401                 :            :     { MsgKey::UNFINISHED, "Block started but not finished by the 'end' "
     402                 :            :       "keyword." },
     403                 :            :     { MsgKey::VORTICAL_UNFINISHED, "Specifying the vortical flow test problem "
     404                 :            :       "requires the specification of parameters alpha, beta, and p0. The error"
     405                 :            :       "is in the block finished above the line above." },
     406                 :            :     { MsgKey::ENERGY_UNFINISHED, "Specifying the nonlinear energy growth test "
     407                 :            :       "problem requires the specification of parameters alpha, betax, betay, "
     408                 :            :       "betaz, ce, kappa, and r0. The error is in the block finished above the "
     409                 :            :       "line above."},
     410                 :            :     { MsgKey::RT_UNFINISHED, "Specifying Reyleigh-Taylor test problem "
     411                 :            :       "requires the specification of parameters alpha, betax, betay, betaz, "
     412                 :            :       "kappa, r0, and p0. The error is in the block finished above the line "
     413                 :            :       "above."},
     414                 :            :     { MsgKey::BC_EMPTY, "Error in the preceding block. Empty boundary "
     415                 :            :       "condition specifications, e.g., 'sideset end', are not allowed." },
     416                 :            :     { MsgKey::SYSFCTVAR, "Error in the system-FCT variable definition block. "
     417                 :            :       "The block must list integers between 1 and 5 both inclusive." },
     418                 :            :     { MsgKey::BGMATIDMISSING, "Error in the preceding block. "
     419                 :            :       "The block must contain background material id." },
     420                 :            :     { MsgKey::BOXMATIDMISSING, "Error in the preceding block. "
     421                 :            :       "Each IC box must specify material id in the box." },
     422                 :            :     { MsgKey::BOXMATIDWRONG, "Error in the preceding block. "
     423                 :            :       "Material id in IC box larger than number of materials." },
     424                 :            :     { MsgKey::STAGBCWRONG, "Stagnation boundary conditions incorrectly "
     425                 :            :       "configured. Within a bc_stag ... end block there must be a point ... "
     426                 :            :       "end block and a radius ... end block. Both point and radius blocks must "
     427                 :            :       "contain floating-point numbers, and the number of items in the point "
     428                 :            :       "block must be exactly 3x that of radii." },
     429                 :            :     { MsgKey::SKIPBCWRONG, "Skip boundary conditions incorrectly "
     430                 :            :       "configured. Within a bc_skip ... end block there must be a point ... "
     431                 :            :       "end block and a radius ... end block. Both point and radius blocks must "
     432                 :            :       "contain floating-point numbers, and the number of items in the point "
     433                 :            :       "block must be exactly 3x that of radii." },
     434                 :            :     { MsgKey::SPONGEBCWRONG, "Sponge symmetry boundary conditions incorrectly "
     435                 :            :       "configured. Within a bc_sym ... end block, if a sponge parameter vector "
     436                 :            :       "is given, its size must equal the number of side sets configured for "
     437                 :            :       "symmetry BCs, and each entry must be between 0.0 and 1.0, prescribing "
     438                 :            :       "the percentage of absorption at the boundary." },
     439                 :            :     { MsgKey::NONDISJOINTBC, "Different boundary condition types are assigned "
     440                 :            :       "to the same side set." },
     441                 :            :     { MsgKey::WRONGSIZE, "Error in the preceding line or block. The size of "
     442                 :            :       "the parameter vector is incorrect." },
     443                 :            :     { MsgKey::WRONGMESHMOTION, "Error in the preceding line or block. Mesh "
     444                 :            :       "motion dimension list can only involve the integers 0, 1, and 2, and "
     445                 :            :       "the size of the list of dimensions must be lower than 4 and larger "
     446                 :            :       "than 0." },
     447                 :            :     { MsgKey::STEADYALE, "Error in the preceding line or block. Arbitrary "
     448                 :            :       "Lagrangian-Eulerian mesh motion is not supported together with marching "
     449                 :            :       "to steady state." },
     450                 :            :     { MsgKey::INCOMPLETEUSERFN, "Error in the preceding line or block. "
     451                 :            :       "Incomplete user-defined function. This usually means the number of "
     452                 :            :       "entries in list is either empty (i.e., the function is not defined) or "
     453                 :            :       "the number of entries is larger than zero but it is not divisible by "
     454                 :            :       "the correct number. For example, if a R->R^3 function is expected the "
     455                 :            :       "number of descrete entries must be divisible by 4: one 'column' for "
     456                 :            :       "the abscissa, and 3 for the ordinate." },
     457                 :            :     { MsgKey::HYDROTIMESCALES, "Error in the preceding line or block. "
     458                 :            :       "Specification of a 'hydrotimescales' vector missing." },
     459                 :            :     { MsgKey::HYDROPRODUCTIONS, "Error in the preceding line or block. "
     460                 :            :       "Specification of a 'hydroproductions' vector missing." },
     461                 :            :     { MsgKey::POSITION_DEPVAR, "Error in the preceding line or block. "
     462                 :            :       "Specification of a dependent variable, configured as a coupled position "
     463                 :            :       "model, is missing. Specify a dependent variable in an equation block "
     464                 :            :       "as, e.g., depvar x, then use 'position x' within the block in question, "
     465                 :            :       "e.g., velocity." },
     466                 :            :     { MsgKey::DISSIPATION_DEPVAR, "Error in the preceding line or block. "
     467                 :            :       "Specification of a dependent variable, configured as a coupled "
     468                 :            :       "dissipation model, is missing. Specify a dependent variable in an "
     469                 :            :       "equation block as, e.g., depvar x, then use 'dissipation x' within the "
     470                 :            :       "block in question, e.g., velocity." },
     471                 :            :     { MsgKey::MIXMASSFRACBETA_DEPVAR, "Error in the preceding line or block. "
     472                 :            :       "Specification of a dependent variable, configured as a coupled "
     473                 :            :       "mass fraction model, is missing. Specify a dependent variable in an "
     474                 :            :       "equation block as, e.g., depvar x, then use 'massfraction x' within the "
     475                 :            :       "block in question, e.g., velocity." },
     476                 :            :     { MsgKey::VELOCITY_DEPVAR, "Error in the preceding line or block. "
     477                 :            :       "Specification of a dependent variable, configured as a coupled velocity "
     478                 :            :       "model, is missing. Specify a dependent variable in an equation block "
     479                 :            :       "as, e.g., depvar u, then use 'velocity u' within the block in question, "
     480                 :            :       "e.g., position." },
     481                 :            :     { MsgKey::POSITION_MISSING, "Specification for a position model missing." },
     482                 :            :     { MsgKey::VELOCITY_MISSING, "Specification for a velocity model missing." },
     483                 :            :     { MsgKey::DISSIPATION_MISSING,
     484                 :            :       "Specification for a dissipation model missing." },
     485                 :            :     { MsgKey::MIXDIR_RHO,
     486                 :            :       "The MixDirichlet SDE parameter vector rho is inconsistent. Its size "
     487                 :            :       "must be ncomp-1 and must be listed in non-decreasing order." },
     488                 :            :     { MsgKey::T0REFODD, "Error in the preceding line or block. "
     489                 :            :       "The number of edge-nodes, marking edges as pairs of nodes, used for "
     490                 :            :       "explicit tagging of edges for initial mesh refineoment is odd (it must "
     491                 :            :       "be even)." },
     492                 :            :     { MsgKey::T0REFNOOP, "Initial (t<0) mesh refinement configuration will be a"
     493                 :            :       " no-op. Initial mesh refinement requires in the amr ... end block: (1) "
     494                 :            :       "'" +  kw::amr_t0ref::string() + " true' and at least one initial "
     495                 :            :       "refinement type, e.g., '" + kw::amr_initial::string() + ' ' +
     496                 :            :       kw::amr_uniform::string() + "'." },
     497                 :            :     { MsgKey::DTREFNOOP, "Mesh refinement configuration for t>0 will be a "
     498                 :            :       "no-op. During-timestepping (t>0) mesh refinement configuration "
     499                 :            :       "requires in the amr ... end block: (1) '" + kw::amr_dtref::string() +
     500                 :            :       " true' and (2) a specification of at least one refinement variable, "
     501                 :            :       "e.g., '" + kw::amr_refvar::string() + " c end'." },
     502                 :            :     { MsgKey::PREFTOL, "The p-refinement tolerance must be a real number "
     503                 :            :       "between 0.0 and 1.0, both inclusive." },
     504                 :            :     { MsgKey::CHARMARG, "Arguments starting with '+' are assumed to be inteded "
     505                 :            :       "for the Charm++ runtime system. Did you forget to prefix the command "
     506                 :            :       "line with charmrun? If this warning persists even after running with "
     507                 :            :       "charmrun, then Charm++ does not understand it either. See the Charm++ "
     508                 :            :       "manual at http://charm.cs.illinois.edu/manuals/html/charm++/"
     509                 :            :       "manual.html." },
     510                 :            :     { MsgKey::OPTIONAL, "This is not really an error message and thus it "
     511                 :            :       "should not be used as one. But its key can be used to indicate "
     512                 :            :       "something optional (which is not an error), which in some situations is "
     513                 :            :       "not optional (which is an error)." }
     514                 :            :   };
     515                 :            : 
     516                 :            :   //! Parser error and warning message handler.
     517                 :            :   //! \details This function is used to associated and dispatch an error or a
     518                 :            :   //!   warning during parsing. After finding the error message corresponding to
     519                 :            :   //!   a key, it pushes back the message to a std::vector of std::string, which
     520                 :            :   //!   then will be diagnosed later by tk::FileParser::diagnostics. The
     521                 :            :   //!   template arguments define (1) the grammar stack (Stack, a tagged tuple)
     522                 :            :   //!   to operate on, (2) the message type (error or warning), and (3) the
     523                 :            :   //!   message key used to look up the error message associated with the key.
     524                 :            :   //! \param[in,out] stack Grammar stack (a tagged tuple) to operate on
     525                 :            :   //! \param[in] in Last parsed PEGTL input token (can be empty, depending on
     526                 :            :   //!   what context this function gets called.
     527                 :            :   template< class Stack, MsgType type, MsgKey key, class Input >
     528                 :          0 :   static void Message( Stack& stack, const Input& in ) {
     529                 :            :     const auto& msg = message.find(key);
     530         [ -  - ]:          0 :     if (msg != message.end()) {
     531                 :          0 :       std::stringstream ss;
     532 [ -  - ][ -  - ]:          0 :       const std::string typestr( type == MsgType::ERROR ? "Error" : "Warning" );
     533                 :            :       auto pos = in.position();
     534         [ -  - ]:          0 :       if (!in.empty()) {
     535                 :          0 :         ss << typestr << " while parsing '" << in.string() << "' at "
     536 [ -  - ][ -  - ]:          0 :            << pos.line << ',' << pos.byte_in_line << ". " << msg->second;
     537                 :            :       } else {
     538         [ -  - ]:          0 :         ss << typestr << " while parsing at " << pos.line << ','
     539         [ -  - ]:          0 :            << pos.byte_in_line << ". " << msg->second;
     540                 :            :       }
     541 [ -  - ][ -  - ]:          0 :       stack.template get< tag::error >().push_back( ss.str() );
     542                 :            :     } else {
     543 [ -  - ][ -  - ]:          0 :       stack.template get< tag::error >().push_back(
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
                 [ -  - ]
     544                 :            :         std::string("Unknown parser ") +
     545                 :            :         (type == MsgType::ERROR ? "error" : "warning" ) +
     546                 :            :         " with no location information." );
     547                 :            :     }
     548                 :          0 :   }
     549                 :            : 
     550                 :            :   #if defined(__clang__)
     551                 :            :     #pragma clang diagnostic push
     552                 :            :     #pragma clang diagnostic ignored "-Wunused-local-typedef"
     553                 :            :   #elif defined(STRICT_GNUC)
     554                 :            :     #pragma GCC diagnostic push
     555                 :            :     #pragma GCC diagnostic ignored "-Wunused-local-typedefs"
     556                 :            :   #endif
     557                 :            :   //! Compile-time test functor verifying that type U is a keyword
     558                 :            :   //! \details This functor is used for triggering a compiler error if any of
     559                 :            :   //!   the expected option values is not in the keywords pool of the grammar.
     560                 :            :   //!   It is used inside of a brigand::for_each to run a compile-time loop
     561                 :            :   //!   over an type sequence, e.g., a list, which verifies that each type in
     562                 :            :   //!   the list is a valid keyword that defines the type 'pegtl_string'.
     563                 :            :   //!  \see kw::keyword in Control/Keyword.h
     564                 :            :   //!  \see e.g. store_option
     565                 :            :   template< template< class > class use >
     566                 :            :   struct is_keyword {
     567                 :            :     template< typename U > void operator()( brigand::type_<U> ) {
     568                 :            :       // Attempting to define the type below accomplishes triggering an error if
     569                 :            :       // the type does not define pegtl_string. The compiler, however, does not
     570                 :            :       // see that far, and generates a warning: unused type alias 'kw', so we
     571                 :            :       // ignore it around this template.
     572                 :            :       using kw = typename use< U >::pegtl_string;
     573                 :            :     }
     574                 :            :   };
     575                 :            :   #if defined(__clang__)
     576                 :            :     #pragma clang diagnostic pop
     577                 :            :   #elif defined(STRICT_GNUC)
     578                 :            :     #pragma GCC diagnostic pop
     579                 :            :   #endif
     580                 :            : 
     581                 :            :   #if defined(__clang__)
     582                 :            :     #pragma clang diagnostic push
     583                 :            :     #pragma clang diagnostic ignored "-Wunused-template"
     584                 :            :   #endif
     585                 :            :   //! \brief Put option (i.e., a tk::Toggle) in grammar state (or stack) at a
     586                 :            :   //!   position given by tags
     587                 :            :   //! \details This function is used to store an option (an object deriving from
     588                 :            :   //!   tk::Toggle) into the grammar stack. See walker::ctr::DiffEq for an
     589                 :            :   //!   example specialization of tk::Toggle to see how an option is created
     590                 :            :   //!   from tk::Toggle.) The grammar stack is a hiearchical tagged tuple and
     591                 :            :   //!   the variadic list of template arguments, tags..., are used to specify
     592                 :            :   //!   a series tags (empty structs, see Control/Tags.h) addressing a
     593                 :            :   //!   particular field of the tagged tuple, i.e., one tag for every additional
     594                 :            :   //!   depth level.
     595                 :            :   //! \param[in,out] stack Grammar stack (a tagged tuple) to operate on
     596                 :            :   //! \param[in] in Last parsed PEGTL input token
     597                 :            :   //! \param[in] defaults Reference to a copy of the full grammar stack at the
     598                 :            :   //!   initial state, i.e., containing the defaults for all of its fields. This
     599                 :            :   //!   is used to detect if the user wants to overwrite an option value that
     600                 :            :   //!   has already been set differently from the default
     601                 :            :   template< class Stack, template< class > class use, class Option,
     602                 :            :             class DefaultStack, class Input, class... tags >
     603                 :            :   static void store_option( Stack& stack,
     604                 :            :                             const Input& in,
     605                 :            :                             const DefaultStack& defaults ) {
     606                 :            :     Option opt;
     607                 :            :     auto value = in.string();
     608                 :            :     if (opt.exist(value)) {
     609                 :            :       auto pos = in.position();
     610                 :            :       // Emit warning on overwriting a non-default option value. This is
     611                 :            :       // slightly inelegant. To be more elegant, we could simply call Message()
     612                 :            :       // here, but the warning message can be more customized here (inside of
     613                 :            :       // this function) and thus produces a more user-friendly message, compared
     614                 :            :       // to a static message that Message() operates with due to its generic
     615                 :            :       // nature. Instead, we emit this more user-friendly message here
     616                 :            :       // (during parsing), instead of after parsing as part of the final parser-
     617                 :            :       // diagnostics. We still provide location information here though.
     618                 :            :       if (stack.template get< tags... >() != opt.value( value ) &&
     619                 :            :           stack.template get< tags... >() != defaults.template get< tags... >())
     620                 :            :         g_print << "\n>>> WARNING: Multiple definitions for '"
     621                 :            :                 << opt.group() << "' option. Overwriting '"
     622                 :            :                 << opt.name( stack.template get< tags... >() ) << "' with '"
     623                 :            :                 << opt.name( opt.value( value ) ) << "' at "
     624                 :            :                 << pos.line << ',' << pos.byte_in_line << ".\n\n";
     625                 :            :       stack.template get< tags... >() = opt.value( value );
     626                 :            :     } else {
     627                 :            :       Message< Stack, ERROR, MsgKey::NOOPTION >( stack, in );
     628                 :            :     }
     629                 :            :     // trigger error at compile-time if any of the expected option values
     630                 :            :     // is not in the keywords pool of the grammar
     631                 :            :     brigand::for_each< typename Option::keywords >( is_keyword< use >() );
     632                 :            :   }
     633                 :            :   #if defined(__clang__)
     634                 :            :     #pragma clang diagnostic pop
     635                 :            :   #endif
     636                 :            : 
     637                 :            :   // Common PEGTL actions (PEGTL actions reused by multiple grammars)
     638                 :            : 
     639                 :            :   //! PEGTL action base: do nothing by default
     640                 :            :   //! \details This base is specialized to different actions duing parsing.
     641                 :            :   template< typename Rule >
     642                 :            :   struct action : pegtl::nothing< Rule > {};
     643                 :            : 
     644                 :            :   //! Helper for calling action::apply for multiple actions
     645                 :            :   template< typename... As >
     646                 :            :   struct call {
     647                 :            :     template< typename Input, typename State >
     648                 :            :     static void apply( const Input& in, State& state ) {
     649                 :            :         using swallow = bool[];
     650 [ -  - ][ -  - ]:          0 :         (void)swallow{ ( action< As >::apply( in, state ), true )..., true };
                 [ -  - ]
     651                 :            :      }
     652                 :            :   };
     653                 :            : 
     654                 :            :   //! Rule used to trigger action(s) for a rule
     655                 :            :   template< class rule, class... actions >
     656                 :            :   struct act : rule {};
     657                 :            : 
     658                 :            :   //! \details Specialization of action for act< rule, actions... >
     659                 :            :   template< class rule, class... actions >
     660                 :            :   struct action< act< rule, actions... > > : call< actions... > {};
     661                 :            : 
     662                 :            :   //! Rule used to trigger action
     663                 :            :   template< MsgType, MsgKey > struct msg : pegtl::success {};
     664                 :            :   //! Error message dispatch
     665                 :            :   //! \details This struct and its apply function are used to dispatch a message
     666                 :            :   //!   (e.g., error, waring) from the parser. It is simply an interface to
     667                 :            :   //!   Message. See This struct is practically used as a functor, i.e., a
     668                 :            :   //!   struct or class that defines the function call operator, but instead the
     669                 :            :   //!   function call operator, PEGTL uses the apply() member function for the
     670                 :            :   //!   actions. Thus this struct can be passed to, i.e., specialize a template,
     671                 :            :   //!   such as tk::grm::unknown, injecting in it the desired behavior.
     672                 :            :   template< MsgType type, MsgKey key >
     673                 :            :   struct action< msg< type, key > > {
     674                 :            :     template< typename Input, typename Stack >
     675                 :            :     static void apply( const Input& in, Stack& stack ) {
     676 [ -  - ][ -  - ]:          0 :       Message< Stack, type, key >( stack, in );
         [ -  - ][ -  - ]
                 [ -  - ]
     677                 :            :     }
     678                 :            :   };
     679                 :            : 
     680                 :            :   //! Rule used to trigger action
     681                 :            :   template< typename tag, typename... tags > struct Set : pegtl::success {};
     682                 :            :   //! Put value in state at position given by tags without conversion
     683                 :            :   //! \details This struct and its apply function are used as a functor-like
     684                 :            :   //!    wrapper for calling the set member function of the underlying grammar
     685                 :            :   //!    stack, tk::Control::set.
     686                 :            :   template< typename tag, typename... tags >
     687                 :            :   struct action< Set< tag, tags... > > {
     688                 :            :     template< typename Input, typename Stack >
     689                 :            :     static void apply( const Input& in, Stack& stack ) {
     690                 :            :       stack.template get< tag, tags... >() = in.string();
     691                 :            :     }
     692                 :            :   };
     693                 :            : 
     694                 :            :   //! Rule used to trigger action
     695                 :            :   template< typename tag, typename... tags > struct Store : pegtl::success {};
     696                 :            :   //! Put value in state at position given by tags with conversion
     697                 :            :   //! \details This struct and its apply function are used as a functor-like
     698                 :            :   //!    wrapper for calling the store member function of the underlying grammar
     699                 :            :   //!    stack, tk::Control::store.
     700                 :            :   template< typename tag, typename... tags >
     701                 :            :   struct action< Store< tag, tags... > > {
     702                 :            :     template< typename Input, typename Stack >
     703                 :          0 :     static void apply( const Input& in, Stack& stack ) {
     704         [ -  - ]:          0 :       if (!in.string().empty())
     705                 :          0 :         stack.template store< tag, tags... >( in.string() );
     706                 :            :       else
     707                 :          0 :         Message< Stack, ERROR, MsgKey::MISSING >( stack, in );
     708                 :          0 :     }
     709                 :            :   };
     710                 :            : 
     711                 :            :   //! Rule used to trigger action
     712                 :            :   template< typename tag, typename... tags >
     713                 :            :   struct Store_back : pegtl::success {};
     714                 :            :   //! Convert and push back value to vector in state at position given by tags
     715                 :            :   //! \details This struct and its apply function are used as a functor-like
     716                 :            :   //!    wrapper for calling the store_back member function of the underlying
     717                 :            :   //!    grammar stack, tk::Control::store_back.
     718                 :            :   template< typename tag, typename...tags >
     719                 :            :   struct action< Store_back< tag, tags... > > {
     720                 :            :     template< typename Input, typename Stack >
     721                 :            :     static void apply( const Input& in, Stack& stack ) {
     722                 :            :       stack.template store_back< tag, tags... >( in.string() );
     723                 :            :     }
     724                 :            :   };
     725                 :            : 
     726                 :            :   //! Rule used to trigger action
     727                 :            :   template< typename tag, typename... tags >
     728                 :            :   struct Store_back_bool : pegtl::success {};
     729                 :            :   //! \brief Convert and push back a bool to vector of ints in state at position
     730                 :            :   //!    given by tags
     731                 :            :   //! \details This struct and its apply function are used as a functor-like
     732                 :            :   //!    wrapper for calling the store_back member function of the underlying
     733                 :            :   //!    grammar stack, tk::Control::store_back.
     734                 :            :   template< typename tag, typename...tags >
     735                 :            :   struct action< Store_back_bool< tag, tags... > > {
     736                 :            :     template< typename Input, typename Stack >
     737                 :            :     static void apply( const Input& in, Stack& stack ) {
     738                 :            :       stack.template store_back_bool< tag, tags... >( in.string() );
     739                 :            :     }
     740                 :            :   };
     741                 :            : 
     742                 :            :   //! Rule used to trigger action
     743                 :            :   template< typename tag, typename... tags >
     744                 :            :   struct Store_back_back : pegtl::success {};
     745                 :            :   //! \brief Convert and push back value to vector of back of vector in state at
     746                 :            :   //!    position given by tags
     747                 :            :   //! \details This struct and its apply function are used as a functor-like
     748                 :            :   //!    wrapper for calling the store_back_back member function of the
     749                 :            :   //!    underlying grammar stack, tk::Control::store_back_back.
     750                 :            :   template< typename tag, typename...tags >
     751                 :            :   struct action< Store_back_back< tag, tags... > > {
     752                 :            :     template< typename Input, typename Stack >
     753                 :            :     static void apply( const Input& in, Stack& stack ) {
     754                 :            :       stack.template store_back_back< tag, tags... >( in.string() );
     755                 :            :     }
     756                 :            :   };
     757                 :            : 
     758                 :            :   //! Rule used to trigger action
     759                 :            :   template< typename tag, typename... tags >
     760                 :            :   struct Store_back_back_back : pegtl::success {};
     761                 :            :   //! \brief Convert and push back value to vector of back of vector of back of
     762                 :            :   //!   vector in state at position given by tags
     763                 :            :   //! \details This struct and its apply function are used as a functor-like
     764                 :            :   //!    wrapper for calling the store_back_back_back member function of the
     765                 :            :   //!    underlying grammar stack, tk::Control::store_back_back_back.
     766                 :            :   template< typename tag, typename...tags >
     767                 :            :   struct action< Store_back_back_back< tag, tags... > > {
     768                 :            :     template< typename Input, typename Stack >
     769                 :            :     static void apply( const Input& in, Stack& stack ) {
     770                 :            :       stack.template store_back_back_back< tag, tags... >( in.string() );
     771                 :            :     }
     772                 :            :   };
     773                 :            : 
     774                 :            :   //! Rule used to trigger action
     775                 :            :   template< typename target, typename tag, typename... tags >
     776                 :            :   struct Back_back_store : pegtl::success {};
     777                 :            :   //! \brief Convert and store value to vector of vector in state at position
     778                 :            :   //!   given by tags and target
     779                 :            :   //! \details This struct and its apply function are used as a functor-like
     780                 :            :   //!    wrapper for calling the store_back member function of the underlying
     781                 :            :   //!    grammar stack. tag and tags... address a vector of vectors, whose
     782                 :            :   //!    inner value_type is a tagged tuple to which we store here after
     783                 :            :   //!    conversion, indexed by target.
     784                 :            :   template< typename target, typename tag, typename...tags >
     785                 :            :   struct action< Back_back_store< target, tag, tags... > > {
     786                 :            :     template< typename Input, typename Stack >
     787                 :            :     static void apply( const Input& in, Stack& stack ) {
     788                 :            :       stack.template get< tag, tags... >().back().back().template
     789                 :            :         store< target >( in.string() );
     790                 :            :     }
     791                 :            :   };
     792                 :            : 
     793                 :            :   //! Rule used to trigger action
     794                 :            :   template< typename target, typename subtarget, typename tag,
     795                 :            :             typename... tags >
     796                 :            :   struct Back_back_deep_store : pegtl::success {};
     797                 :            :   //! \brief Convert and store value to vector of vector in state at position
     798                 :            :   //!   given by tags and target
     799                 :            :   //! \details This struct and its apply function are used as a functor-like
     800                 :            :   //!    wrapper for calling the store_back member function of the underlying
     801                 :            :   //!    grammar stack. tag and tags... address a vector of vectors, whose
     802                 :            :   //!    inner value_type is a tagged tuple to which we store here after
     803                 :            :   //!    conversion, indexed by target and subtarget (hence deep).
     804                 :            :   template< typename target, typename subtarget, typename tag, typename...tags >
     805                 :            :   struct action< Back_back_deep_store< target, subtarget, tag, tags... > > {
     806                 :            :     template< typename Input, typename Stack >
     807                 :            :     static void apply( const Input& in, Stack& stack ) {
     808                 :            :       stack.template get< tag, tags... >().back().back().template
     809                 :            :         store< target, subtarget >( in.string() );
     810                 :            :     }
     811                 :            :   };
     812                 :            : 
     813                 :            :   //! Rule used to trigger action
     814                 :            :   template< typename target, typename tag, typename... tags >
     815                 :            :   struct Back_back_store_back : pegtl::success {};
     816                 :            :   //! \brief Convert and store value to vector of vector in state at position
     817                 :            :   //!   given by tags and target
     818                 :            :   //! \details This struct and its apply function are used as a functor-like
     819                 :            :   //!    wrapper for calling the store_back member function of the underlying
     820                 :            :   //!    grammar stack. tag and tags... address a vector of vectors, whose
     821                 :            :   //!    inner value_type is a tagged tuple to which we store_back here after
     822                 :            :   //!    conversion, indexed by target.
     823                 :            :   template< typename target, typename tag, typename...tags >
     824                 :            :   struct action< Back_back_store_back< target, tag, tags... > > {
     825                 :            :     template< typename Input, typename Stack >
     826                 :            :     static void apply( const Input& in, Stack& stack ) {
     827                 :            :       stack.template get< tag, tags... >().back().back().template
     828                 :            :         store_back< target >( in.string() );
     829                 :            :     }
     830                 :            :   };
     831                 :            : 
     832                 :            :   //! Rule used to trigger action
     833                 :            :   template< typename target, typename tag, typename... tags >
     834                 :            :   struct Back_store_back : pegtl::success {};
     835                 :            :   //! \brief Convert and store value to vector in state at position
     836                 :            :   //!   given by tags and target
     837                 :            :   //! \details This struct and its apply function are used as a functor-like
     838                 :            :   //!    wrapper for calling the store_back member function of the underlying
     839                 :            :   //!    grammar stack.
     840                 :            :   template< typename target, typename tag, typename...tags >
     841                 :            :   struct action< Back_store_back< target, tag, tags... > > {
     842                 :            :     template< typename Input, typename Stack >
     843                 :            :     static void apply( const Input& in, Stack& stack ) {
     844                 :            :       stack.template get< tag, tags... >().back().template
     845                 :            :         store_back< target >( in.string() );
     846                 :            :     }
     847                 :            :   };
     848                 :            : 
     849                 :            :   //! Rule used to trigger action
     850                 :            :   template< typename target, typename subtarget, typename tag,
     851                 :            :             typename... tags >
     852                 :            :   struct Back_back_deep_store_back : pegtl::success {};
     853                 :            :   //! \brief Convert and store value to vector of vector in state at position
     854                 :            :   //!   given by tags and target
     855                 :            :   //! \details This struct and its apply function are used as a functor-like
     856                 :            :   //!    wrapper for calling the store_back member function of the underlying
     857                 :            :   //!    grammar stack. tag and tags... address a vector of vectors, whose
     858                 :            :   //!    inner value_type is a tagged tuple to which we store_back here after
     859                 :            :   //!    conversion, indexed by target and subtarget (hence deep).
     860                 :            :   template< typename target, typename subtarget, typename tag, typename...tags >
     861                 :            :   struct action< Back_back_deep_store_back< target, subtarget, tag, tags... > >
     862                 :            :   {
     863                 :            :     template< typename Input, typename Stack >
     864                 :            :     static void apply( const Input& in, Stack& stack ) {
     865                 :            :       stack.template get< tag, tags... >().back().back().template
     866                 :            :         store_back< target, subtarget >( in.string() );
     867                 :            :     }
     868                 :            :   };
     869                 :            : 
     870                 :            :   //! Rule used to trigger action
     871                 :            :   template< typename... tags >
     872                 :            :   struct Invert_switch : pegtl::success {};
     873                 :            :   //! Invert bool in switch at position given by tags
     874                 :            :   //! \details This struct and its apply function are used as a functor-like
     875                 :            :   //!    wrapper for setting a boolean value to true in the underlying grammar
     876                 :            :   //!    stack via the member function tk::Control::set.
     877                 :            :   template< typename... tags >
     878                 :            :   struct action< Invert_switch< tags... > > {
     879                 :            :     template< typename Input, typename Stack >
     880                 :            :     static void apply( const Input&, Stack& stack ) {
     881                 :          1 :       stack.template get< tags... >() = !stack.template get< tags... >();
     882                 :            :     }
     883                 :            :   };
     884                 :            : 
     885                 :            :   //! Rule used to trigger action
     886                 :            :   template< template < class > class use, class Option,
     887                 :            :             typename tag, typename... tags >
     888                 :            :   struct store_back_option : pegtl::success {};
     889                 :            :   //! Push back option to vector in state at position given by tags
     890                 :            :   //! \details This struct and its apply function are used as a functor-like
     891                 :            :   //!   wrapper for pushing back an option (an object deriving from
     892                 :            :   //!   tk::Toggle) into a vector in the grammar stack. See walker::ctr::DiffEq
     893                 :            :   //!   for an example specialization of tk::Toggle to see how an option is
     894                 :            :   //!   created from tk::Toggle. We also do a simple sanity check here testing
     895                 :            :   //!   if the desired option value exist for the particular option type and
     896                 :            :   //!   error out if there is a problem. Errors and warnings are accumulated
     897                 :            :   //!   during parsing and diagnostics are given after the parsing is finished.
     898                 :            :   template< template < class > class use, class Option,
     899                 :            :             typename tag, typename... tags >
     900                 :            :   struct action< store_back_option< use, Option, tag, tags... > > {
     901                 :            :     template< typename Input, typename Stack >
     902                 :            :     static void apply( const Input& in, Stack& stack ) {
     903                 :            :       Option opt;
     904                 :            :       if (opt.exist(in.string())) {
     905                 :            :         stack.template get<tag,tags...>().push_back( opt.value( in.string() ) );
     906                 :            :       } else {
     907                 :            :         Message< Stack, ERROR, MsgKey::NOOPTION >( stack, in );
     908                 :            :       }
     909                 :            :       // trigger error at compile-time if any of the expected option values
     910                 :            :       // is not in the keywords pool of the grammar
     911                 :            :       brigand::for_each< typename Option::keywords >( is_keyword< use >() );
     912                 :            :     }
     913                 :            :   };
     914                 :            : 
     915                 :            :   //! Rule used to trigger action
     916                 :            :   template< template < class > class use, class Option,
     917                 :            :             typename tag, typename... tags >
     918                 :            :   struct store_back_back_option : pegtl::success {};
     919                 :            :   //! \brief Push back option to vector of back of vector in state at position
     920                 :            :   //!   given by tags
     921                 :            :   //! \details This struct and its apply function are used as a functor-like
     922                 :            :   //!   wrapper for pushing back an option (an object deriving from
     923                 :            :   //!   tk::Toggle) into the back of a vector of a vector in the grammar stack.
     924                 :            :   //!   See walker::ctr::DiffEq for an example specialization of tk::Toggle to
     925                 :            :   //!   see how an option is created from tk::Toggle. We also do a simple sanity
     926                 :            :   //!   check here testing if the desired option value exist for the particular
     927                 :            :   //!   option type and error out if there is a problem. Errors and warnings are
     928                 :            :   //!   accumulated during parsing and diagnostics are given after the parsing
     929                 :            :   //!   is finished. This functor is similar to store_back_option but pushes the
     930                 :            :   //!   option back to a vector of a vector.
     931                 :            :   template< template < class > class use, class Option,
     932                 :            :             typename tag, typename... tags >
     933                 :            :   struct action< store_back_back_option< use, Option, tag, tags... > > {
     934                 :            :     template< typename Input, typename Stack >
     935                 :            :     static void apply( const Input& in, Stack& stack ) {
     936                 :            :       Option opt;
     937                 :            :       if (opt.exist(in.string())) {
     938                 :            :         stack.template get<tag,tags...>().back().
     939                 :            :               push_back( opt.value( in.string() ) );
     940                 :            :       } else {
     941                 :            :         Message< Stack, ERROR, MsgKey::NOOPTION >( stack, in );
     942                 :            :       }
     943                 :            :       // trigger error at compile-time if any of the expected option values
     944                 :            :       // is not in the keywords pool of the grammar
     945                 :            :       brigand::for_each< typename Option::keywords >( is_keyword< use >() );
     946                 :            :     }
     947                 :            :   };
     948                 :            : 
     949                 :            :   //! Rule used to trigger action
     950                 :            :   template< typename target, template < class > class use,
     951                 :            :             class Option, typename tag, typename... tags >
     952                 :            :   struct back_back_store_option : pegtl::success {};
     953                 :            :   //! \brief Push back option to vector of back of vector in state at position
     954                 :            :   //!   given by tags
     955                 :            :   //! \details This struct and its apply function are used as a functor-like
     956                 :            :   //!   wrapper for storing an option (an object deriving from tk::Toggle) in
     957                 :            :   //!   a place in the stack. tag and tags... address a vector of vectors, whose
     958                 :            :   //!   inner value_type is a nested tagged tuple whose field in where we store
     959                 :            :   //!   here after conversion, indexed by target.
     960                 :            :   //!   See walker::ctr::DiffEq for an example specialization of tk::Toggle to
     961                 :            :   //!   see how an option is created from tk::Toggle. We also do a simple sanity
     962                 :            :   //!   check here testing if the desired option value exist for the particular
     963                 :            :   //!   option type and error out if there is a problem. Errors and warnings are
     964                 :            :   //!   accumulated during parsing and diagnostics are given after the parsing
     965                 :            :   //!   is finished.
     966                 :            :   template< typename target, template < class > class use,
     967                 :            :             class Option, typename tag, typename... tags >
     968                 :            :   struct action< back_back_store_option< target, use, Option, tag, tags... > >
     969                 :            :   {
     970                 :            :     template< typename Input, typename Stack >
     971                 :            :     static void apply( const Input& in, Stack& stack ) {
     972                 :            :       Option opt;
     973                 :            :       if (opt.exist(in.string())) {
     974                 :            :         stack.template get< tag, tags... >().back().back().template
     975                 :            :           get< target >() = opt.value( in.string() );
     976                 :            :       } else {
     977                 :            :         Message< Stack, ERROR, MsgKey::NOOPTION >( stack, in );
     978                 :            :       }
     979                 :            :       // trigger error at compile-time if any of the expected option values
     980                 :            :       // is not in the keywords pool of the grammar
     981                 :            :       brigand::for_each< typename Option::keywords >( is_keyword< use >() );
     982                 :            :     }
     983                 :            :   };
     984                 :            : 
     985                 :            :   //! Rule used to trigger action
     986                 :            :   template< typename target, template < class > class use,
     987                 :            :             class Option, typename tag, typename... tags >
     988                 :            :   struct back_store_option : pegtl::success {};
     989                 :            :   //! \brief Push back option to back of vector in state at position
     990                 :            :   //!   given by tags
     991                 :            :   //! \details This struct and its apply function are used as a functor-like
     992                 :            :   //!   wrapper for storing an option (an object deriving from tk::Toggle) in
     993                 :            :   //!   a place in the stack. tag and tags... address a vector, whose
     994                 :            :   //!   inner value_type is a nested tagged tuple whose field in where we store
     995                 :            :   //!   here after conversion, indexed by target.
     996                 :            :   //!   See walker::ctr::DiffEq for an example specialization of tk::Toggle to
     997                 :            :   //!   see how an option is created from tk::Toggle. We also do a simple sanity
     998                 :            :   //!   check here testing if the desired option value exist for the particular
     999                 :            :   //!   option type and error out if there is a problem. Errors and warnings are
    1000                 :            :   //!   accumulated during parsing and diagnostics are given after the parsing
    1001                 :            :   //!   is finished.
    1002                 :            :   template< typename target, template < class > class use,
    1003                 :            :             class Option, typename tag, typename... tags >
    1004                 :            :   struct action< back_store_option< target, use, Option, tag, tags... > >
    1005                 :            :   {
    1006                 :            :     template< typename Input, typename Stack >
    1007                 :            :     static void apply( const Input& in, Stack& stack ) {
    1008                 :            :       Option opt;
    1009                 :            :       if (opt.exist(in.string())) {
    1010                 :            :         stack.template get< tag, tags... >().back().template
    1011                 :            :           get< target >() = opt.value( in.string() );
    1012                 :            :       } else {
    1013                 :            :         Message< Stack, ERROR, MsgKey::NOOPTION >( stack, in );
    1014                 :            :       }
    1015                 :            :       // trigger error at compile-time if any of the expected option values
    1016                 :            :       // is not in the keywords pool of the grammar
    1017                 :            :       brigand::for_each< typename Option::keywords >( is_keyword< use >() );
    1018                 :            :     }
    1019                 :            :   };
    1020                 :            : 
    1021                 :            :   //! Rule used to trigger action
    1022                 :            :   template< typename target, typename subtarget, template < class > class use,
    1023                 :            :             class Option, typename tag, typename... tags >
    1024                 :            :   struct back_back_deep_store_option : pegtl::success {};
    1025                 :            :   //! \brief Push back option to vector of back of vector in state at position
    1026                 :            :   //!   given by tags
    1027                 :            :   //! \details This struct and its apply function are used as a functor-like
    1028                 :            :   //!   wrapper for storing an option (an object deriving from tk::Toggle) in
    1029                 :            :   //!   a place in the stack. tag and tags... address a vector of vectors, whose
    1030                 :            :   //!   inner value_type is a nested tagged tuple whose field in where we store
    1031                 :            :   //!   here after conversion, indexed by target and subtarget.
    1032                 :            :   //!   See walker::ctr::DiffEq for an example specialization of tk::Toggle to
    1033                 :            :   //!   see how an option is created from tk::Toggle. We also do a simple sanity
    1034                 :            :   //!   check here testing if the desired option value exist for the particular
    1035                 :            :   //!   option type and error out if there is a problem. Errors and warnings are
    1036                 :            :   //!   accumulated during parsing and diagnostics are given after the parsing
    1037                 :            :   //!   is finished.
    1038                 :            :   template< typename target, typename subtarget, template < class > class use,
    1039                 :            :             class Option, typename tag, typename... tags >
    1040                 :            :   struct action< back_back_deep_store_option< target, subtarget, use, Option,
    1041                 :            :                  tag, tags... > >
    1042                 :            :   {
    1043                 :            :     template< typename Input, typename Stack >
    1044                 :            :     static void apply( const Input& in, Stack& stack ) {
    1045                 :            :       Option opt;
    1046                 :            :       if (opt.exist(in.string())) {
    1047                 :            :         stack.template get< tag, tags... >().back().back().template
    1048                 :            :           get< target, subtarget >() = opt.value( in.string() );
    1049                 :            :       } else {
    1050                 :            :         Message< Stack, ERROR, MsgKey::NOOPTION >( stack, in );
    1051                 :            :       }
    1052                 :            :       // trigger error at compile-time if any of the expected option values
    1053                 :            :       // is not in the keywords pool of the grammar
    1054                 :            :       brigand::for_each< typename Option::keywords >( is_keyword< use >() );
    1055                 :            :     }
    1056                 :            :   };
    1057                 :            : 
    1058                 :            :   //! Rule used to trigger action
    1059                 :            :   template< typename sel, typename vec, typename Tag, typename... Tags >
    1060                 :            :   struct insert_seed : pegtl::success {};
    1061                 :            :   //! \brief Convert and insert value to map at position given by tags
    1062                 :            :   //! \details This struct and its apply function are used as a functor-like
    1063                 :            :   //!   wrapper for inserting a value into a std::map behind a key in the
    1064                 :            :   //!   underlying grammar stack via the member function tk::Control::insert.
    1065                 :            :   //!   We detect a recently inserted key from the companion tuple field,
    1066                 :            :   //!   "selected vector", given by types, sel and vec, and use that key to
    1067                 :            :   //!   insert an associated value in a std::map addressed by tag and tags...,
    1068                 :            :   //!   requiring at least one tag to address the map. As an example, this is
    1069                 :            :   //!   used in parsing parameters associated to a particular random number
    1070                 :            :   //!   generator, such as seed. Example input file: "mkl_mcg59 seed 2134
    1071                 :            :   //!   uniform_method accurate end". The selected vector here is the
    1072                 :            :   //!   std::vector< tk::ctr::RNGType > under tag::sel.
    1073                 :            :   //! \see Example client-code: tk::rngsse::seed.
    1074                 :            :   template< typename sel, typename vec, typename Tag, typename...Tags >
    1075                 :            :   struct action< insert_seed< sel, vec, Tag, Tags... > > {
    1076                 :            :     template< typename Input, typename Stack >
    1077                 :            :     static void apply( const Input& in, Stack& stack ) {
    1078                 :            :       // get recently inserted key from < sel, vec >
    1079                 :            :       const auto& key = stack.template get< sel, vec >().back();
    1080                 :            :       stack.template
    1081                 :            :         insert_field< tag::seed, kw::seed::info::expect::type, Tag, Tags... >
    1082                 :            :                     ( key, in.string() );
    1083                 :            :     }
    1084                 :            :   };
    1085                 :            : 
    1086                 :            :   //! Rule used to trigger action
    1087                 :            :   template< template< class > class use, class Option,
    1088                 :            :             typename field, typename sel, typename vec,
    1089                 :            :             typename tag, typename... tags >
    1090                 :            :   struct insert_option : pegtl::success {};
    1091                 :            :   //! \brief Convert and insert option value to map at position given by tags
    1092                 :            :   //! \details This struct and its apply function are used as a functor-like
    1093                 :            :   //!   wrapper for converting and inserting an option in a std::map in the
    1094                 :            :   //!   grammar stack. An option is an object deriving from tk::Toggle. See,
    1095                 :            :   //!   e.g., walker::ctr::DiffEq for an example specialization of tk::Toggle to
    1096                 :            :   //!   see how an option is created from tk::Toggle.
    1097                 :            :   template< template< class > class use, class Option,
    1098                 :            :             typename field, typename sel, typename vec, typename tag,
    1099                 :            :             typename... tags >
    1100                 :            :   struct action< insert_option< use, Option, field, sel, vec, tag, tags... > > {
    1101                 :            :     template< typename Input, typename Stack >
    1102                 :            :     static void apply( const Input& in, Stack& stack ) {
    1103                 :            :       // get recently inserted key from <sel,vec>
    1104                 :            :       const auto& key = stack.template get< sel, vec >().back();
    1105                 :            :       stack.template
    1106                 :            :         insert_field< field, typename Option::EnumType, tag, tags... >
    1107                 :            :                     ( key, Option().value(in.string()) );
    1108                 :            :       // trigger error at compile-time if any of the expected option values
    1109                 :            :       // is not in the keywords pool of the grammar
    1110                 :            :       brigand::for_each< typename Option::keywords >( is_keyword< use >() );
    1111                 :            :     }
    1112                 :            :   };
    1113                 :            : 
    1114                 :            :   //! Rule used to trigger action
    1115                 :            :   template< typename prec > struct store_precision : pegtl::success {};
    1116                 :            :   //! \brief Set numeric precision for ASCII output of floating-point values
    1117                 :            :   //! \details This struct and its apply function are used as a functor-like
    1118                 :            :   //!   wrapper for setting the precision used for outputing floating-point
    1119                 :            :   //!   values into text files. We also make sure that the precision to be set
    1120                 :            :   //!   is between the correct bounds of the underlying floating-point type.
    1121                 :            :   //! \see kw::precision_info
    1122                 :            :   template< class prec >
    1123                 :            :   struct action< store_precision< prec > > {
    1124                 :            :     template< typename Input, typename Stack >
    1125                 :            :     static void apply( const Input& in, Stack& stack ) {
    1126                 :            :       using PrEx = kw::precision::info::expect;
    1127                 :            :       std::string low( in.string() );
    1128                 :            :       std::transform( begin(low), end(low), begin(low), ::tolower );
    1129                 :            :       if (low == "max") {
    1130                 :            :         const auto maxprec = PrEx::upper;
    1131                 :            :         stack.template get< tag::prec, prec >() = maxprec;
    1132                 :            :       } else {
    1133                 :            :         PrEx::type precision = std::cout.precision();  // set default
    1134                 :            :         try {   //try to convert matched str to int
    1135                 :            :           precision = std::stol( in.string() );
    1136                 :            :         }
    1137                 :            :         catch ( std::exception& ) {
    1138                 :            :           Message< Stack, ERROR, MsgKey::BADPRECISION >( stack, in );
    1139                 :            :         }
    1140                 :            :         // only set precision given if it makes sense
    1141                 :            :         if (precision >= PrEx::lower && precision <= PrEx::upper)
    1142                 :            :           stack.template get< tag::prec, prec >() = precision;
    1143                 :            :         else
    1144                 :            :           Message< Stack, WARNING, MsgKey::PRECISIONBOUNDS >( stack, in );
    1145                 :            :       }
    1146                 :            :     }
    1147                 :            :   };
    1148                 :            : 
    1149                 :            :   //! Rule used to trigger action
    1150                 :            :   struct helpkw : pegtl::success {};
    1151                 :            :   //! \brief Find keyword among all keywords and if found, store the keyword
    1152                 :            :   //!    and its info on which help was requested behind tag::helpkw in Stack
    1153                 :            :   //! \details This struct and its apply function are used as a functor-like
    1154                 :            :   //!    wrapper to search for a keyword in the pool of registered keywords
    1155                 :            :   //!    recognized by a grammar and store the keyword and its info on which
    1156                 :            :   //!    help was requested behind tag::helpkw. Note that this functor assumes
    1157                 :            :   //!    a specific location for the std::maps of the command-line and control
    1158                 :            :   //!    file keywords pools (behind tag::cmdinfo and tag::ctrinfo,
    1159                 :            :   //!    respectively), and for the keyword and its info on which help was
    1160                 :            :   //!    requested (behind tag::helpkw). This is the structure of CmdLine
    1161                 :            :   //!    objects, thus this functor should be called from command line parsers.
    1162                 :            :   template<>
    1163                 :            :   struct action< helpkw > {
    1164                 :            :     template< typename Input, typename Stack >
    1165                 :          0 :     static void apply( const Input& in, Stack& stack ) {
    1166                 :            :       const auto& cmdinfo = stack.template get< tag::cmdinfo >();
    1167                 :            :       const auto& ctrinfo = stack.template get< tag::ctrinfo >();
    1168         [ -  - ]:          0 :       auto it = cmdinfo.find( in.string() );
    1169         [ -  - ]:          0 :       if (it != cmdinfo.end()) {
    1170                 :            :         // store keyword and its info on which help was requested
    1171                 :          0 :         stack.template get< tag::helpkw >() = { it->first, it->second, true };
    1172                 :            :       } else {
    1173         [ -  - ]:          0 :         it = ctrinfo.find( in.string() );
    1174         [ -  - ]:          0 :         if (it != ctrinfo.end())
    1175                 :            :           // store keyword and its info on which help was requested
    1176                 :          0 :           stack.template get< tag::helpkw >() = { it->first, it->second, false };
    1177                 :            :         else
    1178                 :          0 :           Message< Stack, ERROR, MsgKey::KEYWORD >( stack, in );
    1179                 :            :       }
    1180                 :          0 :     }
    1181                 :            :   };
    1182                 :            : 
    1183                 :            :   //! Rule used to trigger action
    1184                 :            :   template< typename push > struct match_depvar : pegtl::success {};
    1185                 :            :   //! \brief Match depvar (dependent variable) to one of the selected ones
    1186                 :            :   //! \details This is used to check the set of dependent variables previously
    1187                 :            :   //!    assigned to registered differential equations (or models).
    1188                 :            :   template< class push >
    1189                 :            :   struct action< match_depvar< push > > {
    1190                 :            :     template< typename Input, typename Stack >
    1191                 :            :     static void apply( const Input& in, Stack& stack ) {
    1192                 :            :       // convert matched string to char
    1193                 :            :       auto var = stack.template convert< char >( in.string() );
    1194                 :            :       // find matched variable in set of selected ones
    1195                 :            :       if (depvars.find( var ) != depvars.end())
    1196                 :            :         action< push >::apply( in, stack );
    1197                 :            :       else  // error out if matched var is not selected
    1198                 :            :         Message< Stack, ERROR, MsgKey::NOSUCHDEPVAR >( stack, in );
    1199                 :            :     }
    1200                 :            :   };
    1201                 :            : 
    1202                 :            :   //! Rule used to trigger action
    1203                 :            :   struct match_pdfname : pegtl::success {};
    1204                 :            :   //! \brief Match PDF name to the registered ones
    1205                 :            :   //! \details This is used to check the set of PDF names dependent previously
    1206                 :            :   //!    registered to make sure all are unique.
    1207                 :            :   template<>
    1208                 :            :   struct action< match_pdfname > {
    1209                 :            :     template< typename Input, typename Stack >
    1210                 :            :     static void apply( const Input& in, Stack& stack ) {
    1211                 :            :       // find matched name in set of registered ones
    1212                 :            :       if (pdfnames.find( in.string() ) == pdfnames.end()) {
    1213                 :            :         pdfnames.insert( in.string() );
    1214                 :            :         stack.template get< tag::cmd, tag::io, tag::pdfnames >().
    1215                 :            :           push_back( in.string() );
    1216                 :            :       }
    1217                 :            :       else  // error out if name matched var is already registered
    1218                 :            :         Message< Stack, ERROR, MsgKey::PDFEXISTS >( stack, in );
    1219                 :            :     }
    1220                 :            :   };
    1221                 :            : 
    1222                 :            :   //! Rule used to trigger action
    1223                 :            :   template< template< class > class use, class Option, typename sel,
    1224                 :            :             typename vec, typename... tags >
    1225                 :            :   struct check_store_option : pegtl::success {};
    1226                 :            :   //! Put option in state at position given by tags if among the selected
    1227                 :            :   template< template < class > class use, class Option, typename sel,
    1228                 :            :             typename vec, typename... tags >
    1229                 :            :   struct action< check_store_option< use, Option, sel, vec, tags... > > {
    1230                 :            :     template< typename Input, typename Stack >
    1231                 :            :     static void apply( const Input& in, Stack& stack ) {
    1232                 :            :       // error out if chosen item does not exist in selected vector
    1233                 :            :       bool exists = false;
    1234                 :            :       for (const auto& r : stack.template get< sel, vec >()) {
    1235                 :            :         // cppcheck-suppress useStlAlgorithm
    1236                 :            :         if (Option().value(in.string()) == r) exists = true;
    1237                 :            :       }
    1238                 :            :       if (exists)
    1239                 :            :         action< store_back_option< use, Option, tags... > >::apply( in, stack );
    1240                 :            :       else
    1241                 :            :         Message< Stack, ERROR, MsgKey::NOTSELECTED >( stack, in );
    1242                 :            :     }
    1243                 :            :   };
    1244                 :            : 
    1245                 :            :   //! Rule used to trigger action
    1246                 :            :   struct add_depvar : pegtl::success {};
    1247                 :            :   //! Add depvar (dependent variable) to the selected ones
    1248                 :            :   template<>
    1249                 :            :   struct action< add_depvar > {
    1250                 :            :     template< typename Input, typename Stack >
    1251                 :            :     static void apply( const Input& in, Stack& stack ) {
    1252                 :            :       // convert matched string to char
    1253                 :            :       auto newvar = stack.template convert< char >( in.string() );
    1254                 :            :       // put in new dependent variable to set of already selected ones
    1255                 :            :       if (depvars.find( newvar ) == depvars.end())
    1256                 :            :         depvars.insert( newvar );
    1257                 :            :       else  // error out if depvar is already taken
    1258                 :            :         Message< Stack, ERROR, MsgKey::EXISTS >( stack, in );
    1259                 :            :     }
    1260                 :            :   };
    1261                 :            : 
    1262                 :            :   //! Rule used to trigger action
    1263                 :            :   template< class keyword, typename tag, typename... tags >
    1264                 :            :   struct check_lower_bound : pegtl::success {};
    1265                 :            :   //! Check if value is larger than lower bound
    1266                 :            :   template< class keyword, typename tag, typename... tags >
    1267                 :            :   struct action< check_lower_bound< keyword, tag, tags... > > {
    1268                 :            :     template< typename Input, typename Stack >
    1269                 :            :     static void apply( const Input& in, Stack& stack ) {
    1270                 :            :       auto lower = keyword::info::expect::lower;
    1271                 :            :       auto val = stack.template get< tag, tags... >();
    1272                 :            :       if (val < lower) Message< Stack, ERROR, MsgKey::BOUNDS >( stack, in );
    1273                 :            :     }
    1274                 :            :   };
    1275                 :            : 
    1276                 :            :   //! Rule used to trigger action
    1277                 :            :   template< class keyword, typename tag, typename... tags >
    1278                 :            :   struct check_upper_bound : pegtl::success {};
    1279                 :            :   //! Check if value is lower than upper bound
    1280                 :            :   template< class keyword, typename tag, typename... tags >
    1281                 :            :   struct action< check_upper_bound< keyword, tag, tags... > > {
    1282                 :            :     template< typename Input, typename Stack >
    1283                 :            :     static void apply( const Input& in, Stack& stack ) {
    1284                 :            :       auto upper = keyword::info::expect::upper;
    1285                 :            :       auto val = stack.template get< tag, tags... >();
    1286                 :            :       if (val > upper) Message< Stack, ERROR, MsgKey::BOUNDS >( stack, in );
    1287                 :            :     }
    1288                 :            :   };
    1289                 :            : 
    1290                 :            :   //! Rule used to trigger action
    1291                 :            :   template< typename tag, typename... tags >
    1292                 :            :   struct start_vector : pegtl::success {};
    1293                 :            :   //! Start new vector in vector
    1294                 :            :   template< class tag, class... tags >
    1295                 :            :   struct action< start_vector< tag, tags... > > {
    1296                 :            :     template< typename Input, typename Stack >
    1297                 :            :     static void apply( const Input&, Stack& stack ) {
    1298                 :            :       stack.template get< tag, tags... >().emplace_back();
    1299                 :            :     }
    1300                 :            :   };
    1301                 :            : 
    1302                 :            :   //! Rule used to trigger action
    1303                 :            :   template< typename tag, typename... tags >
    1304                 :            :   struct start_vector_back : pegtl::success {};
    1305                 :            :   //! Start new vector in back of a vector
    1306                 :            :   template< class tag, class... tags >
    1307                 :            :   struct action< start_vector_back< tag, tags... > > {
    1308                 :            :     template< typename Input, typename Stack >
    1309                 :            :     static void apply( const Input&, Stack& stack ) {
    1310                 :            :       // no arg: use default ctor
    1311                 :            :       stack.template get< tag, tags... >().back().emplace_back();
    1312                 :            :     }
    1313                 :            :   };
    1314                 :            : 
    1315                 :            :   //! Rule used to trigger action
    1316                 :            :   template< typename tag, typename... tags >
    1317                 :            :   struct start_vector_back_back : pegtl::success {};
    1318                 :            :   //! Start new vector in back of a vector
    1319                 :            :   template< class tag, class... tags >
    1320                 :            :   struct action< start_vector_back_back< tag, tags... > > {
    1321                 :            :     template< typename Input, typename Stack >
    1322                 :            :     static void apply( const Input&, Stack& stack ) {
    1323                 :            :       // no arg: use default ctor
    1324                 :            :       stack.template get< tag, tags... >().back().back().emplace_back();
    1325                 :            :     }
    1326                 :            :   };
    1327                 :            : 
    1328                 :            :   //! Rule used to trigger action
    1329                 :            :   template< typename tk::ctr::Moment, char var = '\0' >
    1330                 :            :   struct push_term : pegtl::success {};
    1331                 :            :   //! Add matched value as Term into vector of vector of statistics
    1332                 :            :   template< tk::ctr::Moment m, char var >
    1333                 :            :   struct action< push_term< m, var > > {
    1334                 :            :     template< typename Input, typename Stack >
    1335                 :            :     static void apply( const Input& in, Stack& stack ) {
    1336                 :            :       // If var is given, push var, otherwise push first char of value
    1337                 :            :       char v(var ? var : in.string()[0]);
    1338                 :            :       // Use a shorthand of reference to vector to push_back to
    1339                 :            :       auto& stats = stack.template get< tag::stat >();
    1340                 :            :       // Push term into current vector
    1341                 :            :       stats.back().emplace_back( tk::ctr::Term( v, field, m ) );
    1342                 :            :       // If central moment, trigger mean (in statistics)
    1343                 :            :       if (m == tk::ctr::Moment::CENTRAL) {
    1344                 :            :         tk::ctr::Term term( static_cast<char>(toupper(v)),
    1345                 :            :                             field,
    1346                 :            :                             tk::ctr::Moment::ORDINARY );
    1347                 :            :         stats.insert( stats.end()-1, tk::ctr::Product( 1, term ) );
    1348                 :            :       }
    1349                 :            :       field = 0;            // reset default field
    1350                 :            :     }
    1351                 :            :   };
    1352                 :            : 
    1353                 :            :   //! Rule used to trigger action
    1354                 :            :   template< tk::ctr::Moment m > struct push_sample : pegtl::success {};
    1355                 :            :   //! Add matched value as Term into vector of vector of PDFs
    1356                 :            :   template< tk::ctr::Moment m >
    1357                 :            :   struct action< push_sample< m > > {
    1358                 :            :     template< typename Input, typename Stack >
    1359                 :            :     static void apply( const Input& in, Stack& stack ) {
    1360                 :            :       // Use a shorthand of reference to vector to push_back to
    1361                 :            :       auto& pdf = stack.template get< tag::pdf >();
    1362                 :            :       // Error out if sample space already has at least 3 dimensions
    1363                 :            :       if ( pdf.back().size() >= 3 ) {
    1364                 :            :         Message< Stack, ERROR, MsgKey::MAXSAMPLES >( stack, in );
    1365                 :            :       }
    1366                 :            :       // Error out if matched sample space variable starts with a digit
    1367                 :            :       if ( std::isdigit(in.string()[0]) )
    1368                 :            :         Message< Stack, ERROR, MsgKey::MALFORMEDSAMPLE >( stack, in );
    1369                 :            :       // Push term into current vector
    1370                 :            :       pdf.back().emplace_back( tk::ctr::Term( in.string()[0], field, m ) );
    1371                 :            :       // If central moment, trigger estimation of mean (in statistics)
    1372                 :            :       if (m == tk::ctr::Moment::CENTRAL) {
    1373                 :            :         tk::ctr::Term term( static_cast<char>(toupper(in.string()[0])),
    1374                 :            :                             field,
    1375                 :            :                             tk::ctr::Moment::ORDINARY );
    1376                 :            :         auto& stats = stack.template get< tag::stat >();
    1377                 :            :         if (!stats.empty())
    1378                 :            :           stats.insert( stats.end()-1, tk::ctr::Product( 1, term ) );
    1379                 :            :         else
    1380                 :            :           stats.emplace_back( tk::ctr::Product( 1, term ) );
    1381                 :            :       }
    1382                 :            :       field = 0;            // reset default field
    1383                 :            :     }
    1384                 :            :   };
    1385                 :            : 
    1386                 :            :   //! Rule used to trigger action
    1387                 :            :   struct push_binsize : pegtl::success {};
    1388                 :            :   //! Push matched value into vector of vector binsizes
    1389                 :            :   template<>
    1390                 :            :   struct action< push_binsize > {
    1391                 :            :     template< typename Input, typename Stack >
    1392                 :            :     static void apply( const Input& in, Stack& stack ) {
    1393                 :            :       // Use a shorthand of reference to vector to push_back to
    1394                 :            :       auto& bins = stack.template get< tag::discr, tag::binsize >().back();
    1395                 :            :       // Error out if binsize vector already has at least 3 dimensions
    1396                 :            :       if ( bins.size() >= 3 ) {
    1397                 :            :         Message< Stack, ERROR, MsgKey::MAXBINSIZES >( stack, in );
    1398                 :            :       }
    1399                 :            :       // Push term into vector if larger than zero
    1400                 :            :       const auto& binsize = stack.template convert< tk::real >( in.string() );
    1401                 :            :       if ( !(binsize > std::numeric_limits< tk::real >::epsilon()) )
    1402                 :            :         Message< Stack, ERROR, MsgKey::ZEROBINSIZE >( stack, in );
    1403                 :            :       else
    1404                 :            :         bins.emplace_back( binsize );
    1405                 :            :     }
    1406                 :            :   };
    1407                 :            : 
    1408                 :            :   //! Rule used to trigger action
    1409                 :            :   struct push_extents : pegtl::success {};
    1410                 :            :   //! Push matched value into vector of PDF extents
    1411                 :            :   template<>
    1412                 :            :   struct action< push_extents > {
    1413                 :            :     template< typename Input, typename Stack >
    1414                 :            :     static void apply( const Input& in, Stack& stack ) {
    1415                 :            :       // Use a shorthand of reference to vector to push_back to
    1416                 :            :       auto& vec = stack.template get< tag::discr, tag::extent >().back();
    1417                 :            :       // Error out if extents vector already has at least 3 pairs
    1418                 :            :       if (vec.size() >= 6)
    1419                 :            :         Message< Stack, ERROR, MsgKey::MAXEXTENTS >( stack, in );
    1420                 :            :       // Error out if extents vector already has the enough pairs to match the
    1421                 :            :       // number of sample space dimensions
    1422                 :            :       if (vec.size() >=
    1423                 :            :           stack.template get< tag::discr, tag::binsize >().back().size() * 2) {
    1424                 :            :         Message< Stack, ERROR, MsgKey::INVALIDEXTENT >( stack, in );
    1425                 :            :       }
    1426                 :            :       // Push extent into vector
    1427                 :            :       vec.emplace_back( stack.template convert< tk::real >( in.string() ) );
    1428                 :            :     }
    1429                 :            :   };
    1430                 :            : 
    1431                 :            :   //! Rule used to trigger action
    1432                 :            :   template< class eq, class param, class... xparam >
    1433                 :            :   struct check_vector : pegtl::success {};
    1434                 :            :   //! Check parameter vector
    1435                 :            :   template< class eq, class param, class... xparam >
    1436                 :            :   struct action< check_vector< eq, param, xparam... > > {
    1437                 :            :     template< typename Input, typename Stack >
    1438                 :            :     static void apply( const Input&, Stack& ) {}
    1439                 :            :   };
    1440                 :            : 
    1441                 :            :   //! Rule used to trigger action
    1442                 :            :   struct noop : pegtl::success {};
    1443                 :            :   //! Action that does nothing
    1444                 :            :   template<>
    1445                 :            :   struct action< noop > {
    1446                 :            :     template< typename Input, typename Stack >
    1447                 :            :     static void apply( const Input&, Stack& ) {}
    1448                 :            :   };
    1449                 :            : 
    1450                 :            :   //! Rule used to trigger action
    1451                 :            :   template< class eq, class param, class... xparam >
    1452                 :            :   struct check_spikes : pegtl::success {};
    1453                 :            :   //! Check if the spikes parameter vector specifications are correct
    1454                 :            :   //! \details Spikes are used to specify sample-space locations and relative
    1455                 :            :   //!    probability heights for a joint-delta PDF.
    1456                 :            :   template< class eq, class param, class... xparam >
    1457                 :            :   struct action< check_spikes< eq, param, xparam... > > {
    1458                 :            :     template< typename Input, typename Stack >
    1459                 :            :     static void apply( const Input& in, Stack& stack ) {
    1460                 :            :       const auto& spike =
    1461                 :            :         stack.template get< tag::param, eq, param, xparam... >().back().back();
    1462                 :            :       // Error out if the number of spikes-vector is odd
    1463                 :            :       if (spike.size() % 2)
    1464                 :            :         Message< Stack, ERROR, MsgKey::ODDSPIKES >( stack, in );
    1465                 :            :       // Error out if the sum of spike heights does not add up to unity, but
    1466                 :            :       // only if the spike block is not empty (an empty spike..end block
    1467                 :            :       // is okay and is used to specify no delta spikes for a dependent
    1468                 :            :       // variable).
    1469                 :            :       if (!spike.empty()) {
    1470                 :            :         tk::real sum = 0.0;
    1471                 :            :         for (std::size_t i=1; i<spike.size(); i+=2)  // every even is a height
    1472                 :            :           sum += spike[i];
    1473                 :            :         if (std::abs(sum-1.0) > std::numeric_limits< tk::real >::epsilon())
    1474                 :            :           Message< Stack, ERROR, MsgKey::HEIGHTSPIKES >( stack, in );
    1475                 :            :       }
    1476                 :            :     }
    1477                 :            :   };
    1478                 :            : 
    1479                 :            :   //! Rule used to trigger action
    1480                 :            :   template< class eq, class param, class... xparam >
    1481                 :            :   struct check_betapdfs : pegtl::success {};
    1482                 :            :   //! Check if the betapdf parameter vector specifications are correct
    1483                 :            :   //! \details Betapdf vectors are used to configure univariate beta
    1484                 :            :   //!   distributions.
    1485                 :            :   template< class eq, class param, class... xparam >
    1486                 :            :   struct action< check_betapdfs< eq, param, xparam... > > {
    1487                 :            :     template< typename Input, typename Stack >
    1488                 :            :     static void apply( const Input& in, Stack& stack ) {
    1489                 :            :       const auto& betapdf =
    1490                 :            :         stack.template get< tag::param, eq, param, xparam... >().back().back();
    1491                 :            :       // Error out if the number parameters is not four
    1492                 :            :       if (betapdf.size() != 4)
    1493                 :            :         Message< Stack, ERROR, MsgKey::WRONGBETAPDF >( stack, in );
    1494                 :            :     }
    1495                 :            :   };
    1496                 :            : 
    1497                 :            :   //! Rule used to trigger action
    1498                 :            :   template< class eq, class param, class... xparam >
    1499                 :            :   struct check_gammapdfs : pegtl::success {};
    1500                 :            :   //! Check if the gammapdf parameter vector specifications are correct
    1501                 :            :   //! \details gammapdf vectors are used to configure univariate gamma
    1502                 :            :   //!   distributions.
    1503                 :            :   template< class eq, class param, class... xparam >
    1504                 :            :   struct action< check_gammapdfs< eq, param, xparam... > > {
    1505                 :            :     template< typename Input, typename Stack >
    1506                 :            :     static void apply( const Input& in, Stack& stack ) {
    1507                 :            :       const auto& gamma =
    1508                 :            :         stack.template get< tag::param, eq, param, xparam... >().back().back();
    1509                 :            :       // Error out if the number parameters is not two
    1510                 :            :       if (gamma.size() != 2)
    1511                 :            :         Message< Stack, ERROR, MsgKey::WRONGGAMMAPDF >( stack, in );
    1512                 :            :       // Error out if the specified shape or scale parameter negative
    1513                 :            :       if (gamma[0] < 0.0 || gamma[1] < 0.0)
    1514                 :            :         Message< Stack, ERROR, MsgKey::NEGATIVEPARAM >( stack, in );
    1515                 :            :     }
    1516                 :            :   };
    1517                 :            : 
    1518                 :            :   //! Rule used to trigger action
    1519                 :            :   template< class eq, class param, class... xparam >
    1520                 :            :   struct check_dirichletpdf : pegtl::success {};
    1521                 :            :   //! Check if the dirichletpdf parameter vector specifications are correct
    1522                 :            :   //! \details dirichletpdf vectors are used to configure multivariate
    1523                 :            :   //!    Dirichlet distributions.
    1524                 :            :   template< class eq, class param, class... xparam >
    1525                 :            :   struct action< check_dirichletpdf< eq, param, xparam... > > {
    1526                 :            :     template< typename Input, typename Stack >
    1527                 :            :     static void apply( const Input& in, Stack& stack ) {
    1528                 :            :       const auto& dir =
    1529                 :            :         stack.template get< tag::param, eq, param, xparam... >().back();
    1530                 :            :       // get recently configured eq block number of scalar components
    1531                 :            :       auto ncomp =
    1532                 :            :         stack.template get< tag::component >().template get< eq >().back();
    1533                 :            :       // Error out if the number parameters does not equal ncomp
    1534                 :            :       if (dir.size() != ncomp-2)
    1535                 :            :         Message< Stack, ERROR, MsgKey::WRONGDIRICHLET >( stack, in );
    1536                 :            :       // Error out if the specified shape or scale parameter negative
    1537                 :            :       for (auto a : dir)
    1538                 :            :         if (a < 0.0)
    1539                 :            :           Message< Stack, ERROR, MsgKey::NEGATIVEPARAM >( stack, in );
    1540                 :            :     }
    1541                 :            :   };
    1542                 :            : 
    1543                 :            :   //! Rule used to trigger action
    1544                 :            :   template< class eq, class param, class... xparam >
    1545                 :            :   struct check_gaussians : pegtl::success {};
    1546                 :            :   //! Check if the Gaussian PDF parameter vector specifications are correct
    1547                 :            :   //! \details Gaussian vectors are used to configure univariate Gaussian
    1548                 :            :   //!   distributions.
    1549                 :            :   template< class eq, class param, class... xparam >
    1550                 :            :   struct action< check_gaussians< eq, param, xparam... > > {
    1551                 :            :     template< typename Input, typename Stack >
    1552                 :            :     static void apply( const Input& in, Stack& stack ) {
    1553                 :            :       const auto& gaussian =
    1554                 :            :         stack.template get< tag::param, eq, param, xparam... >().back().back();
    1555                 :            :       // Error out if the number parameters is not two
    1556                 :            :       if (gaussian.size() != 2)
    1557                 :            :         Message< Stack, ERROR, MsgKey::WRONGGAUSSIAN >( stack, in );
    1558                 :            :       // Error out if the specified variance is negative
    1559                 :            :       if (gaussian.back() < 0.0)
    1560                 :            :         Message< Stack, ERROR, MsgKey::NEGATIVEPARAM >( stack, in );
    1561                 :            :     }
    1562                 :            :   };
    1563                 :            : 
    1564                 :            :   //! Rule used to trigger action
    1565                 :            :   struct check_expectation : pegtl::success {};
    1566                 :            :   //! Check if there is at least one variable in expectation
    1567                 :            :   template<>
    1568                 :            :   struct action< check_expectation > {
    1569                 :            :     template< typename Input, typename Stack >
    1570                 :            :     static void apply( const Input& in, Stack& stack ) {
    1571                 :            :       if (stack.template get< tag::stat >().back().empty())
    1572                 :            :         Message< Stack, ERROR, MsgKey::NOTERMS >( stack, in );
    1573                 :            :     }
    1574                 :            :   };
    1575                 :            : 
    1576                 :            :   //! Rule used to trigger action
    1577                 :            :   struct check_binsizes : pegtl::success {};
    1578                 :            :   //! Check if the number of binsizes equal the PDF sample space variables
    1579                 :            :   template<>
    1580                 :            :   struct action< check_binsizes > {
    1581                 :            :     template< typename Input, typename Stack >
    1582                 :            :     static void apply( const Input& in, Stack& stack ) {
    1583                 :            :       if (stack.template get< tag::pdf >().back().size() !=
    1584                 :            :           stack.template get< tag::discr, tag::binsize >().back().size())
    1585                 :            :           Message< Stack, ERROR, MsgKey::BINSIZES >( stack, in );
    1586                 :            :     }
    1587                 :            :   };
    1588                 :            : 
    1589                 :            :   //! Rule used to trigger action
    1590                 :            :   struct check_extents : pegtl::success {};
    1591                 :            :   //! Check if the number of extents equal 2 * the PDF sample space variables
    1592                 :            :   template<>
    1593                 :            :   struct action< check_extents > {
    1594                 :            :     template< typename Input, typename Stack >
    1595                 :            :     static void apply( const Input& in, Stack& stack ) {
    1596                 :            :       // Use a shorthand to extents vector
    1597                 :            :       const auto& e = stack.template get< tag::discr, tag::extent >().back();
    1598                 :            :       // Check if the number of extents are correct
    1599                 :            :       if (!e.empty() &&
    1600                 :            :           e.size() !=
    1601                 :            :             stack.template get< tag::discr, tag::binsize >().back().size()*2)
    1602                 :            :         Message< Stack, ERROR, MsgKey::INVALIDEXTENT >( stack, in );
    1603                 :            :       // Check if the lower extents are indeed lower than the higher extents
    1604                 :            :       if (e.size() > 1 && e[0] > e[1])
    1605                 :            :         Message< Stack, ERROR, MsgKey::EXTENTLOWER >( stack, in );
    1606                 :            :       if (e.size() > 3 && e[2] > e[3])
    1607                 :            :         Message< Stack, ERROR, MsgKey::EXTENTLOWER >( stack, in );
    1608                 :            :       if (e.size() > 5 && e[4] > e[5])
    1609                 :            :         Message< Stack, ERROR, MsgKey::EXTENTLOWER >( stack, in );
    1610                 :            :     }
    1611                 :            :   };
    1612                 :            : 
    1613                 :            :   //! Rule used to trigger action
    1614                 :            :   struct check_samples : pegtl::success {};
    1615                 :            :   //! Check if there is at least one sample space variable in PDF
    1616                 :            :   template<>
    1617                 :            :   struct action< check_samples > {
    1618                 :            :     template< typename Input, typename Stack >
    1619                 :            :     static void apply( const Input& in, Stack& stack ) {
    1620                 :            :       if (stack.template get< tag::pdf >().back().empty())
    1621                 :            :         Message< Stack, ERROR, MsgKey::NOSAMPLES >( stack, in );
    1622                 :            :     }
    1623                 :            :   };
    1624                 :            : 
    1625                 :            :   //! Rule used to trigger action
    1626                 :            :   struct save_field : pegtl::success {};
    1627                 :            :   //! Save field ID to parser's state so push_term can pick it up
    1628                 :            :   template<>
    1629                 :            :   struct action< save_field > {
    1630                 :            :     template< typename Input, typename Stack >
    1631                 :            :     static void apply( const Input& in, Stack& stack ) {
    1632                 :            :       // field ID numbers start at 0
    1633                 :            :       auto f = stack.template convert< long >( in.string() ) - 1;
    1634                 :            :       if (f < 0)
    1635                 :            :         Message< Stack, ERROR, MsgKey::POSITIVECOMPONENT >( stack, in );
    1636                 :            :       field = static_cast< ncomp_t >( f );
    1637                 :            :     }
    1638                 :            :   };
    1639                 :            : 
    1640                 :            :   //! Rule used to trigger action
    1641                 :            :   template< typename Tag, typename... Tags >
    1642                 :            :   struct store_lua : pegtl::success {};
    1643                 :            :   //! Append character parsed in a lua ... end block to a string
    1644                 :            :   template< typename Tag, typename... Tags >
    1645                 :            :   struct action< store_lua< Tag, Tags... > > {
    1646                 :            :     template< typename Input, typename Stack >
    1647                 :            :     static void apply( const Input& in, Stack& stack ) {
    1648                 :            :       stack.template get< Tag, Tags..., tag::lua >().back() += in.string();
    1649                 :            :     }
    1650                 :            :   };
    1651                 :            : 
    1652                 :            :   // Common grammar (grammar that is reused by multiple grammars)
    1653                 :            : 
    1654                 :            :   //! Read 'token' until 'erased' trimming, i.e., not consuming, 'erased'
    1655                 :            :   template< class token, class erased >
    1656                 :            :   struct trim :
    1657                 :            :          pegtl::seq< token,
    1658                 :            :                      pegtl::sor<
    1659                 :            :                        pegtl::until< pegtl::at< erased > >,
    1660                 :            :                        msg< ERROR, MsgKey::PREMATURE > > > {};
    1661                 :            : 
    1662                 :            :   //! Match unknown keyword and handle error
    1663                 :            :   template< MsgType type, MsgKey key >
    1664                 :            :   struct unknown :
    1665                 :            :          pegtl::pad< pegtl::seq< trim< pegtl::any, pegtl::space >,
    1666                 :            :                                  msg< type, key > >,
    1667                 :            :                      pegtl::blank,
    1668                 :            :                      pegtl::space > {};
    1669                 :            : 
    1670                 :            :   //! Match alias cmdline keyword
    1671                 :            :   //! \details An alias command line keyword is prefixed by a single dash, '-'.
    1672                 :            :   template< class keyword >
    1673                 :            :   struct alias :
    1674                 :            :          pegtl::seq<
    1675                 :            :            pegtl::one< '-' >,
    1676                 :            :            typename keyword::info::alias::type,
    1677                 :            :            pegtl::sor< pegtl::space,
    1678                 :            :                        msg< ERROR, MsgKey::ALIAS > >  > {};
    1679                 :            : 
    1680                 :            :   //! Match verbose cmdline keyword
    1681                 :            :   //! \details A verbose command line keyword is prefixed by a double-dash,
    1682                 :            :   //!   '--'.
    1683                 :            :   template< class keyword >
    1684                 :            :   struct verbose :
    1685                 :            :          pegtl::seq< pegtl::string<'-','-'>,
    1686                 :            :                      typename keyword::pegtl_string,
    1687                 :            :                      pegtl::space > {};
    1688                 :            : 
    1689                 :            :   //! Read keyword 'token' padded by blank at left and space at right
    1690                 :            :   template< class token >
    1691                 :            :   struct readkw :
    1692                 :            :          pegtl::pad< trim< token, pegtl::space >,
    1693                 :            :                      pegtl::blank,
    1694                 :            :                      pegtl::space > {};
    1695                 :            : 
    1696                 :            :   //! Read command line 'keyword' in verbose form, i.e., '--keyword'
    1697                 :            :   //! \details This version is used if no alias is defined for the given keyword
    1698                 :            :   template< class keyword, typename = void >
    1699                 :            :   struct readcmd :
    1700                 :            :          verbose< keyword > {};
    1701                 :            : 
    1702                 :            :   //! Read command line 'keyword' in either verbose or alias form
    1703                 :            :   //! \details This version is used if an alias is defined for the given
    1704                 :            :   //!   keyword, in which case either the verbose or the alias form of the
    1705                 :            :   //!   keyword is matched, i.e., either '--keyword' or '-a', where 'a' is the
    1706                 :            :   //!   single-character alias for the longer 'keyword'. This is a partial
    1707                 :            :   //!   specialization of the simpler verbose-only readcmd, which attempts to
    1708                 :            :   //!   find the typedef 'alias' in keyword::info. If it finds it, it uses this
    1709                 :            :   //!   specialization. If it fails, it is [SFINAE]
    1710                 :            :   //!   (http://en.cppreference.com/w/cpp/language/sfinae), and falls back to
    1711                 :            :   //!   the verbose-only definition. Credit goes to David Rodriguez at
    1712                 :            :   //!   stackoverflow.com. This allows not having to change this client-code to
    1713                 :            :   //!   the keywords definitions: a keyword either defines an alias or not, and
    1714                 :            :   //!   the grammar here will do the right thing: if there is an alias, it will
    1715                 :            :   //!   build the grammar that optionally parses for it.
    1716                 :            :   //! \see tk::if_
    1717                 :            :   //! \see Control/Keyword.h and Control/Keywords.h
    1718                 :            :   //! \see http://en.cppreference.com/w/cpp/language/sfinae
    1719                 :            :   //! \see http://stackoverflow.com/a/11814074
    1720                 :            :   template< class keyword >
    1721                 :            :   struct readcmd< keyword,
    1722                 :            :                   typename if_< false, typename keyword::info::alias >::type > :
    1723                 :            :          pegtl::sor< verbose< keyword >, alias< keyword > > {};
    1724                 :            : 
    1725                 :            :   //! \brief Scan input padded by blank at left and space at right and if it
    1726                 :            :   //!   matches 'keyword', apply 'actions'
    1727                 :            :   //! \details As opposed to scan_until this rule, allows multiple actions
    1728                 :            :   template< class keyword, class... actions >
    1729                 :            :   struct scan :
    1730                 :            :          pegtl::pad< act< trim< keyword, pegtl::space >, actions... >,
    1731                 :            :                      pegtl::blank,
    1732                 :            :                      pegtl::space > {};
    1733                 :            : 
    1734                 :            :   //! \brief Scan input padded by blank at left and space at right and if it
    1735                 :            :   //!   matches 'keywords', apply 'action'
    1736                 :            :   //! \details This version uses an additional custom end rule. As opposed
    1737                 :            :   //!   to scan, this rule allows an additional end-rule until which parsing is
    1738                 :            :   //!   continued. The additional custom end-rule is OR'd to pegtl::space.
    1739                 :            :   template< class keywords, class action, class end = pegtl::space >
    1740                 :            :   struct scan_until :
    1741                 :            :          pegtl::pad< act< trim< keywords, pegtl::sor< pegtl::space, end > >,
    1742                 :            :                           action >,
    1743                 :            :                      pegtl::blank,
    1744                 :            :                      pegtl::space > {};
    1745                 :            : 
    1746                 :            :   //! \brief Scan input padded by blank at left and space at right and if it
    1747                 :            :   //!   exactly matches 'keyword', apply 'actions'
    1748                 :            :   template< class keyword, class... actions >
    1749                 :            :   struct exact_scan :
    1750                 :            :          pegtl::pad< act< pegtl::until< typename keyword::pegtl_string,
    1751                 :            :                                         pegtl::space >, actions... >,
    1752                 :            :                      pegtl::blank,
    1753                 :            :                      pegtl::space > {};
    1754                 :            : 
    1755                 :            :   //! Parse comment: start with '#' until eol
    1756                 :            :   struct comment :
    1757                 :            :          pegtl::pad< trim< pegtl::one<'#'>, pegtl::eol >,
    1758                 :            :                      pegtl::blank,
    1759                 :            :                      pegtl::eol > {};
    1760                 :            : 
    1761                 :            :   //! Ignore comments and empty lines
    1762                 :            :   struct ignore :
    1763                 :            :          pegtl::sor< comment, pegtl::until< pegtl::eol, pegtl::space > > {};
    1764                 :            : 
    1765                 :            :   //! Parse a number: an optional sign followed by digits
    1766                 :            :   struct number :
    1767                 :            :          pegtl::seq< pegtl::opt< pegtl::sor< pegtl::one<'+'>,
    1768                 :            :                                              pegtl::one<'-'> > >,
    1769                 :            :                      pegtl::digit > {};
    1770                 :            : 
    1771                 :            :   //! Plow through 'tokens' until 'endkeyword'
    1772                 :            :   template< class endkeyword, typename... tokens >
    1773                 :            :   struct block :
    1774                 :            :          pegtl::until<
    1775                 :            :            readkw< typename endkeyword::pegtl_string >,
    1776                 :            :            pegtl::sor< comment,
    1777                 :            :                        ignore,
    1778                 :            :                        tokens...,
    1779                 :            :                        unknown< ERROR, MsgKey::KEYWORD > > > {};
    1780                 :            : 
    1781                 :            :   //! \brief Read in list of dimensions between keywords 'key' and
    1782                 :            :   //!   'endkeyword', calling 'insert' for each if matches and allow comments
    1783                 :            :   //!   between values
    1784                 :            :   template< class key, class insert, class endkeyword,
    1785                 :            :             class starter = noop, class value = pegtl::digit >
    1786                 :            :   struct dimensions :
    1787                 :            :          pegtl::seq<
    1788                 :            :            act< readkw< typename key::pegtl_string >, starter >,
    1789                 :            :            block< endkeyword, scan< value, insert > > > {};
    1790                 :            : 
    1791                 :            :   //! Plow through vector of values between keywords 'key' and
    1792                 :            :   //!   'endkeyword', calling 'insert' for each if matches and allow comments
    1793                 :            :   //!   between values
    1794                 :            :   template< class key, class insert, class endkeyword,
    1795                 :            :             class starter = noop, class value = number >
    1796                 :            :   // cppcheck-suppress syntaxError
    1797                 :            :   struct vector :
    1798                 :            :          pegtl::seq<
    1799                 :            :            act< readkw< typename key::pegtl_string >, starter >,
    1800                 :            :            block< endkeyword, scan< value, insert > > > {};
    1801                 :            : 
    1802                 :            :   //! \brief Scan string between characters 'lbound' and 'rbound' and if matches
    1803                 :            :   //!   apply action 'insert'
    1804                 :            :   template< class insert, char lbound = '"', char rbound = '"' >
    1805                 :            :   struct quoted :
    1806                 :            :          pegtl::if_must< pegtl::one< lbound >,
    1807                 :            :                          act< pegtl::sor< trim< pegtl::not_one< lbound >,
    1808                 :            :                                                 pegtl::one< rbound > >,
    1809                 :            :                                           unknown< ERROR, MsgKey::QUOTED > >,
    1810                 :            :                               insert >,
    1811                 :            :                          pegtl::one< rbound > > {};
    1812                 :            : 
    1813                 :            :   //! Read and store a filename between quotes
    1814                 :            :   template< template< class > class use, class tag, class... tags >
    1815                 :            :   struct filename :
    1816                 :            :           pegtl::if_must<
    1817                 :            :             readkw< typename use< kw::filename >::pegtl_string >,
    1818                 :            :             quoted< Store_back< tag, tags... > > > {};
    1819                 :            : 
    1820                 :            :   //! \brief Process 'keyword' and if matches, parse following token (expecting
    1821                 :            :   //!   'kw_type' and call 'insert' action on it
    1822                 :            :   template< class keyword, class insert, class kw_type = pegtl::digit >
    1823                 :            :   struct process :
    1824                 :            :          pegtl::if_must<
    1825                 :            :            readkw< typename keyword::pegtl_string >,
    1826                 :            :            scan< pegtl::sor< kw_type, msg< ERROR, MsgKey::MISSING > >,
    1827                 :            :                  insert > > {};
    1828                 :            : 
    1829                 :            :   //! \brief Process 'keyword' and if matches, parse following token (expecting
    1830                 :            :   //!   pegtl::alpha and call zero or more actions on it
    1831                 :            :   template< class keyword, class... actions >
    1832                 :            :   struct process_alpha :
    1833                 :            :          pegtl::if_must<
    1834                 :            :            readkw< typename keyword::pegtl_string >,
    1835                 :            :            scan< pegtl::sor< pegtl::alpha, msg< ERROR, MsgKey::MISSING > >,
    1836                 :            :                  actions... > > {};
    1837                 :            : 
    1838                 :            :   //! \brief Process command line 'keyword' and call its 'insert' action if
    1839                 :            :   //!   matches 'kw_type'
    1840                 :            :   template< template< class > class use, class keyword, class insert,
    1841                 :            :             class kw_type, class tag, class... tags >
    1842                 :            :   struct process_cmd :
    1843                 :            :          pegtl::if_must<
    1844                 :            :            readcmd< use< keyword > >,
    1845                 :            :            scan< pegtl::sor< kw_type, msg< ERROR, MsgKey::MISSING > >, insert >,
    1846                 :            :            typename std::conditional<
    1847                 :            :              tk::HasVar_expect_lower< typename keyword::info >::value,
    1848                 :            :              check_lower_bound< keyword, tag, tags... >,
    1849                 :            :              pegtl::success >::type,
    1850                 :            :            typename std::conditional<
    1851                 :            :              tk::HasVar_expect_upper< typename keyword::info >::value,
    1852                 :            :              check_upper_bound< keyword, tag, tags... >,
    1853                 :            :              pegtl::success >::type > {};
    1854                 :            : 
    1855                 :            :   //! Process command line switch 'keyword'
    1856                 :            :   //! \details The value of a command line switch is a boolean, i.e., it can be
    1857                 :            :   //!    either set or unset.
    1858                 :            :   template< template< class > class use, class keyword, typename tag,
    1859                 :            :             typename... tags >
    1860                 :            :   struct process_cmd_switch :
    1861                 :            :          pegtl::seq<readcmd< use<keyword> >, Invert_switch< tag, tags... >> {};
    1862                 :            : 
    1863                 :            :   //! \brief Generic file parser entry point: parse 'keywords' and 'ignore'
    1864                 :            :   //!   until end of file
    1865                 :            :   template< typename keywords, typename... ign >
    1866                 :            :   struct read_file :
    1867                 :            :          pegtl::until< pegtl::eof,
    1868                 :            :                        pegtl::sor<
    1869                 :            :                          keywords,
    1870                 :            :                          ign...,
    1871                 :            :                          unknown< ERROR, MsgKey::KEYWORD > > > {};
    1872                 :            : 
    1873                 :            :   //! Process but ignore Charm++'s charmrun arguments starting with '+'
    1874                 :            :   struct charmarg :
    1875                 :            :          pegtl::seq< pegtl::one<'+'>,
    1876                 :            :                      unknown< WARNING, MsgKey::CHARMARG > > {};
    1877                 :            : 
    1878                 :            :   //! Generic string parser entry point: parse 'keywords' until end of string
    1879                 :            :   template< typename keywords >
    1880                 :            :   struct read_string :
    1881                 :            :          pegtl::until< pegtl::eof,
    1882                 :            :                        pegtl::sor<
    1883                 :            :                          keywords,
    1884                 :            :                          charmarg,
    1885                 :            :                          unknown< ERROR, MsgKey::KEYWORD > > > {};
    1886                 :            : 
    1887                 :            :   //! Insert RNG parameter
    1888                 :            :   //! \details A parameter here is always an option. An option is an object
    1889                 :            :   //!   deriving from tk::Toggle. See, e.g., walker::ctr::DiffEq for an example
    1890                 :            :   //!   specialization of tk::Toggle to see how an option is created from
    1891                 :            :   //!   tk::Toggle.
    1892                 :            :   template< template< class > class use, typename keyword,
    1893                 :            :             typename option, typename field, typename sel, typename vec,
    1894                 :            :             typename... tags >
    1895                 :            :   struct rng_option :
    1896                 :            :          process< keyword,
    1897                 :            :                   insert_option< use, option, field, sel, vec, tags... >,
    1898                 :            :                   pegtl::alpha > {};
    1899                 :            : 
    1900                 :            :   //! \brief Match fieldvar: a character, denoting a variable, optionally
    1901                 :            :   //!   followed by a digit
    1902                 :            :   template< typename var >
    1903                 :            :   struct fieldvar :
    1904                 :            :          pegtl::sor<
    1905                 :            :            pegtl::seq< var, act< pegtl::plus< pegtl::digit >, save_field > >,
    1906                 :            :            var > {};
    1907                 :            : 
    1908                 :            :   //! \brief Match  term: upper or lowercase fieldvar matched to selected
    1909                 :            :   //!    depvars for stats
    1910                 :            :   struct term :
    1911                 :            :          pegtl::sor<
    1912                 :            :            act< fieldvar< pegtl::upper >,
    1913                 :            :                 match_depvar< push_term< tk::ctr::Moment::ORDINARY > > >,
    1914                 :            :            act< fieldvar< pegtl::lower >,
    1915                 :            :                 match_depvar< push_term< tk::ctr::Moment::CENTRAL > > > > {};
    1916                 :            : 
    1917                 :            :   //! \brief sample space variable: fieldvar matched to selected depvars
    1918                 :            :   template< class c, tk::ctr::Moment m >
    1919                 :            :   struct sample_space_var :
    1920                 :            :          scan_until<
    1921                 :            :            fieldvar< c >,
    1922                 :            :            match_depvar< push_sample< m > >,
    1923                 :            :            pegtl::one<':'> > {};
    1924                 :            : 
    1925                 :            :   //! Match samples: sample space variables optionally separated by fillers
    1926                 :            :   struct samples :
    1927                 :            :          pegtl::sor<
    1928                 :            :            sample_space_var< pegtl::upper, tk::ctr::Moment::ORDINARY >,
    1929                 :            :            sample_space_var< pegtl::lower, tk::ctr::Moment::CENTRAL >
    1930                 :            :          > {};
    1931                 :            : 
    1932                 :            :   //! Match bin(sizes): real numbers as many sample space dimensions were given
    1933                 :            :   struct bins :
    1934                 :            :          pegtl::sor<
    1935                 :            :            scan_until< number, push_binsize, pegtl::one<')'> >,
    1936                 :            :            act< pegtl::until< pegtl::at< pegtl::one<')'> >, pegtl::any >,
    1937                 :            :                 msg< ERROR, MsgKey::INVALIDBINSIZE > > > {};
    1938                 :            : 
    1939                 :            :   //! Plow through expectations between characters '<' and '>'
    1940                 :            :   struct parse_expectations :
    1941                 :            :          readkw< pegtl::seq< act< pegtl::one<'<'>, start_vector< tag::stat > >,
    1942                 :            :                              pegtl::until< pegtl::one<'>'>, term >,
    1943                 :            :                              check_expectation > > {};
    1944                 :            : 
    1945                 :            :   //! Match list of sample space variables with error checking
    1946                 :            :   struct sample_space :
    1947                 :            :          pegtl::seq<
    1948                 :            :            start_vector< tag::pdf >,
    1949                 :            :            pegtl::until< pegtl::one<':'>, samples >,
    1950                 :            :            check_samples > {};
    1951                 :            : 
    1952                 :            :   //! Match extents: optional user-specified extents of PDF sample space
    1953                 :            :   struct extents :
    1954                 :            :          pegtl::sor<
    1955                 :            :            scan_until< number, push_extents, pegtl::one<')'> >,
    1956                 :            :            act< pegtl::until< pegtl::at< pegtl::one<')'> >, pegtl::any >,
    1957                 :            :                 msg< ERROR, MsgKey::INVALIDEXTENT > > > {};
    1958                 :            : 
    1959                 :            :   //! Match binsizes followed by optional extents with error checking
    1960                 :            :   struct bins_exts :
    1961                 :            :          pegtl::seq<
    1962                 :            :            start_vector< tag::discr, tag::binsize >,
    1963                 :            :            start_vector< tag::discr, tag::extent >,
    1964                 :            :            pegtl::until< pegtl::sor< pegtl::one<';'>,
    1965                 :            :                                      pegtl::at< pegtl::one<')'> > >,
    1966                 :            :                          bins >,
    1967                 :            :            pegtl::until< pegtl::one<')'>, extents >,
    1968                 :            :            check_binsizes,
    1969                 :            :            check_extents > {};
    1970                 :            : 
    1971                 :            :   //! \brief Match pdf description: name + sample space specification
    1972                 :            :   //! \details Example syntax (without the quotes): "name(x y z : 1.0 2.0 3.0)",
    1973                 :            :   //!    'name' is the name of the pdf, and x,y,z are sample space variables,
    1974                 :            :   //!    while 1.0 2.0 3.0 are bin sizes corresponding to the x y z sample space
    1975                 :            :   //!    dimensions, respectively.
    1976                 :            :   struct parse_pdf :
    1977                 :            :          readkw<
    1978                 :            :            pegtl::if_must<
    1979                 :            :              act< pegtl::seq< pegtl::identifier, pegtl::at< pegtl::one<'('> > >,
    1980                 :            :                   match_pdfname >,
    1981                 :            :              pegtl::sor< pegtl::one<'('>,
    1982                 :            :                          msg< ERROR, MsgKey::KEYWORD > >,
    1983                 :            :              pegtl::sor< pegtl::seq< sample_space, bins_exts >,
    1984                 :            :                          msg< ERROR, MsgKey::INVALIDSAMPLESPACE > > > > {};
    1985                 :            : 
    1986                 :            :   //! Match precision of floating-point numbers in digits (for text output)
    1987                 :            :   template< template< class > class use, class prec >
    1988                 :            :   struct precision :
    1989                 :            :          process< use< kw::precision >,
    1990                 :            :                   store_precision< prec >,
    1991                 :            :                   pegtl::alnum > {};
    1992                 :            : 
    1993                 :            :   //! Match control parameter, enforce bounds if defined
    1994                 :            :   template< typename keyword, class kw_type, template< class... > class store,
    1995                 :            :             typename... tags >
    1996                 :            :   struct control :
    1997                 :            :          pegtl::if_must<
    1998                 :            :            process< keyword, store< tags... >, kw_type >,
    1999                 :            :            typename std::conditional<
    2000                 :            :              tk::HasVar_expect_lower< typename keyword::info >::value,
    2001                 :            :              check_lower_bound< keyword, tags... >,
    2002                 :            :              pegtl::success >::type,
    2003                 :            :            typename std::conditional<
    2004                 :            :              tk::HasVar_expect_upper< typename keyword::info >::value,
    2005                 :            :              check_upper_bound< keyword, tags... >,
    2006                 :            :              pegtl::success >::type > {};
    2007                 :            : 
    2008                 :            :   //! Match discretization control parameter
    2009                 :            :   template< template< class > class use, typename keyword, typename Tag >
    2010                 :            :   struct discrparam :
    2011                 :            :            control< use< keyword >, pegtl::digit, Store, tag::discr, Tag > {};
    2012                 :            : 
    2013                 :            :   //! Match component control parameter
    2014                 :            :   template< typename keyword, typename Tag >
    2015                 :            :   struct component :
    2016                 :            :          process< keyword,
    2017                 :            :                   Store_back< tag::component, Tag >,
    2018                 :            :                   pegtl::digit > {};
    2019                 :            : 
    2020                 :            :   //! Match output interval control parameter in units of iteration count
    2021                 :            :   template< typename keyword, typename Tag, typename... Tags >
    2022                 :            :   struct interval_iter :
    2023                 :            :          control< keyword, pegtl::digit, Store, Tag, Tags... > {};
    2024                 :            : 
    2025                 :            :   //! Match output interval control parameter in units of physics time
    2026                 :            :   template< typename keyword, typename Tag, typename... Tags >
    2027                 :            :   struct interval_time :
    2028                 :            :          control< keyword, number, Store, Tag, Tags... > {};
    2029                 :            : 
    2030                 :            :   //! Match output range control configuration as a list of min, max, and dt
    2031                 :            :   template< template< class > class use, class keyword, class tag,
    2032                 :            :             class... tags >
    2033                 :            :   struct time_range :
    2034                 :            :          pegtl::if_must<
    2035                 :            :            tk::grm::readkw< typename use< keyword >::pegtl_string >,
    2036                 :            :            start_vector< tag, tags... >,
    2037                 :            :            tk::grm::block< use< kw::end >,
    2038                 :            :              tk::grm::scan< tk::grm::number,
    2039                 :            :                tk::grm::Store_back_back< tag, tags... > > > > {};
    2040                 :            : 
    2041                 :            :   //! Parse statistics ... end block
    2042                 :            :   template< template< class > class use, template< class... Ts > class store >
    2043                 :            :   struct statistics :
    2044                 :            :          pegtl::if_must< readkw< typename use< kw::statistics >::pegtl_string >,
    2045                 :            :                          block< use< kw::end >,
    2046                 :            :                                 interval_iter< use< kw::interval_iter >,
    2047                 :            :                                   tag::output, tag::iter, tag::stat >,
    2048                 :            :                                 process< use< kw::txt_float_format >,
    2049                 :            :                                          store< tk::ctr::TxtFloatFormat,
    2050                 :            :                                                 tag::flformat,
    2051                 :            :                                                 tag::stat >,
    2052                 :            :                                          pegtl::alpha >,
    2053                 :            :                                 precision< use, tag::stat >,
    2054                 :            :                                 parse_expectations > > {};
    2055                 :            : 
    2056                 :            :   //! Parse diagnostics ... end block
    2057                 :            :   template< template< class > class use, template< class... Ts > class store >
    2058                 :            :   struct diagnostics :
    2059                 :            :          pegtl::if_must< readkw< typename use< kw::diagnostics >::pegtl_string >,
    2060                 :            :                          block< use< kw::end >,
    2061                 :            :                                 interval_iter< use< kw::interval_iter >,
    2062                 :            :                                   tag::output, tag::iter, tag::diag >,
    2063                 :            :                                 process< use< kw::txt_float_format >,
    2064                 :            :                                          store< tk::ctr::TxtFloatFormat,
    2065                 :            :                                                 tag::flformat,
    2066                 :            :                                                 tag::diag >,
    2067                 :            :                                          pegtl::alpha >,
    2068                 :            :                                 process< use< kw::error >,
    2069                 :            :                                          store_back_option< use,
    2070                 :            :                                                             tk::ctr::Error,
    2071                 :            :                                                             tag::diag,
    2072                 :            :                                                             tag::error >,
    2073                 :            :                                          pegtl::alpha >,
    2074                 :            :                                 precision< use, tag::diag > > > {};
    2075                 :            : 
    2076                 :            :   //! Parse lua ... end block and store it behind Tag, Tags..., tag::lua
    2077                 :            :   template< template< class > class use, typename Tag, typename... Tags >
    2078                 :            :   struct lua :
    2079                 :            :          pegtl::if_must<
    2080                 :            :            readkw< typename use< kw::lua >::pegtl_string >,
    2081                 :            :            start_vector< Tag, Tags..., tag::lua >,
    2082                 :            :            pegtl::until< readkw< typename use< kw::end >::pegtl_string >,
    2083                 :            :                           act< pegtl::any, store_lua< Tag, Tags... > > > > {};
    2084                 :            : 
    2085                 :            :   //! Match model parameter
    2086                 :            :   template< typename keyword, typename kw_type, typename model, typename Tag >
    2087                 :            :   struct parameter :
    2088                 :            :          control< keyword, kw_type, Store, tag::param, model, Tag > {};
    2089                 :            : 
    2090                 :            :   //! Match rng parameter
    2091                 :            :   template< template< class > class use, typename keyword,
    2092                 :            :             typename option, typename model, typename... tags >
    2093                 :            :   struct rng :
    2094                 :            :          process< keyword,
    2095                 :            :                   check_store_option< use,
    2096                 :            :                                       option,
    2097                 :            :                                       tag::selected,
    2098                 :            :                                       tag::rng,
    2099                 :            :                                       tag::param, model, tags... >,
    2100                 :            :                   pegtl::alpha > {};
    2101                 :            : 
    2102                 :            :   //! Match rngs ... end block
    2103                 :            :   template< template< class > class use, class rngs >
    2104                 :            :   struct rngblock :
    2105                 :            :          pegtl::if_must< readkw< typename use< kw::rngs >::pegtl_string >,
    2106                 :            :                          block< use< kw::end >, rngs > > {};
    2107                 :            : 
    2108                 :            :   //! Match equation/model parameter vector
    2109                 :            :   //! \details This structure is used to match a keyword ... end block that
    2110                 :            :   //!   contains a list (i.e., a vector) of numbers. The keyword that starts the
    2111                 :            :   //!   block is passed in via the 'keyword' template argument. The 'store'
    2112                 :            :   //!   argument abstracts away a "functor" used to store the parsed values
    2113                 :            :   //!   (usually a push_back operaton on a std::vector. The 'start' argument
    2114                 :            :   //!   abstracts away the starter functor used to start the inserting operation
    2115                 :            :   //!   before parsing a value (usually a push_back on a vector using the
    2116                 :            :   //!   default value constructor). The 'check' argument abstracts away a
    2117                 :            :   //!   functor used to do error checking on the value parsed. Arguments 'eq'
    2118                 :            :   //!   and 'param' denote two levels of the hierarchy relative to tag::param,
    2119                 :            :   //!   at which the parameter vector lives. Example client-code: see
    2120                 :            :   //!   walker::deck::icbeta, or walker::deck::icdelta.
    2121                 :            :   template< template< class > class use,
    2122                 :            :             typename keyword,
    2123                 :            :             template< class, class... > class store,
    2124                 :            :             template< class, class... > class start,
    2125                 :            :             template< class, class, class... > class check,
    2126                 :            :             typename eq,
    2127                 :            :             typename param,
    2128                 :            :             typename... xparams >
    2129                 :            :   struct parameter_vector :
    2130                 :            :          pegtl::if_must< vector< keyword,
    2131                 :            :                                  store< tag::param, eq, param, xparams... >,
    2132                 :            :                                  use< kw::end >,
    2133                 :            :                                  start< tag::param, eq, param, xparams... > >,
    2134                 :            :                          check< eq, param, xparams... > > {};
    2135                 :            : 
    2136                 :            :   //! Match equation/model option vector
    2137                 :            :   //! \details This structure is used to match a keyword ... end block that
    2138                 :            :   //!   contains a list (i.e., a vector) of numbers. The keyword that starts the
    2139                 :            :   //!   block is passed in via the 'keyword' template argument. The 'store'
    2140                 :            :   //!   argument abstracts away a "functor" used to store the parsed values
    2141                 :            :   //!   (e.g. a push_back operaton on a std::vector. The 'start' argument
    2142                 :            :   //!   abstracts away the starter functor used to start the inserting operation
    2143                 :            :   //!   before parsing a value (usually a push_back on a vector using the
    2144                 :            :   //!   default value constructor). The 'check' argument abstracts away a
    2145                 :            :   //!   functor used to do error checking on the value parsed. Arguments 'eq'
    2146                 :            :   //!   and 'param' denote two levels of the hierarchy relative to tag::param,
    2147                 :            :   //!   at which the parameter vector lives. Example client-code: see
    2148                 :            :   //!   walker::deck::sde_option_vector.
    2149                 :            :   template< template< class > class use,
    2150                 :            :             typename keyword,
    2151                 :            :             class option,
    2152                 :            :             template< class, class... > class store,
    2153                 :            :             template< class, class... > class start,
    2154                 :            :             template< class, class > class check,
    2155                 :            :             typename eq,
    2156                 :            :             typename param >
    2157                 :            :   struct option_vector :
    2158                 :            :          pegtl::if_must<
    2159                 :            :            vector<
    2160                 :            :              keyword,
    2161                 :            :              store_back_back_option< use, option, tag::param, eq, param >,
    2162                 :            :              use< kw::end >,
    2163                 :            :              start< tag::param, eq, param >,
    2164                 :            :              pegtl::alpha >,
    2165                 :            :            check< eq, param > > {};
    2166                 :            : 
    2167                 :            :   //! Match model parameter dependent variable
    2168                 :            :   template< template< class > class use, typename model, typename Tag >
    2169                 :            :   struct depvar :
    2170                 :            :          pegtl::if_must<
    2171                 :            :            readkw< typename use< kw::depvar >::pegtl_string >,
    2172                 :            :            scan< pegtl::sor< pegtl::alpha, msg< ERROR, MsgKey::NOTALPHA > >,
    2173                 :            :                  Store_back< tag::param, model, Tag >,
    2174                 :            :                  add_depvar > > {};
    2175                 :            : 
    2176                 :            :   //! Match and set keyword 'title'
    2177                 :            :   template< template< class > class use >
    2178                 :            :   struct title :
    2179                 :            :          pegtl::if_must< readkw< typename use< kw::title >::pegtl_string >,
    2180                 :            :                          quoted< Set< tag::title > > > {};
    2181                 :            : 
    2182                 :            :   //! Match and set policy parameter
    2183                 :            :   template< template< class > class use, typename keyword,
    2184                 :            :             typename option, typename p, typename... tags >
    2185                 :            :   struct policy :
    2186                 :            :          process<
    2187                 :            :            keyword,
    2188                 :            :            store_back_option< use, option, tag::param, p, tags... >,
    2189                 :            :            pegtl::alpha > {};
    2190                 :            : 
    2191                 :            :   //! Match and set a PDF option
    2192                 :            :   template< class keyword, class store >
    2193                 :            :   struct pdf_option :
    2194                 :            :          process< keyword, store, pegtl::alpha > {};
    2195                 :            : 
    2196                 :            :   //! Match pdfs ... end block
    2197                 :            :   template< template< class > class use, template< class... Ts > class store >
    2198                 :            :   struct pdfs :
    2199                 :            :          pegtl::if_must<
    2200                 :            :            tk::grm::readkw< typename use < kw::pdfs >::pegtl_string >,
    2201                 :            :            tk::grm::block<
    2202                 :            :              use< kw::end >,
    2203                 :            :              tk::grm::interval_iter< use< kw::interval_iter >,
    2204                 :            :                                      tag::output, tag::iter, tag::pdf >,
    2205                 :            :              pdf_option< use< kw::filetype >,
    2206                 :            :                          store< tk::ctr::PDFFile,
    2207                 :            :                                 tag::selected,
    2208                 :            :                                 tag::filetype > >,
    2209                 :            :              pdf_option< use< kw::pdf_policy >,
    2210                 :            :                          store< tk::ctr::PDFPolicy,
    2211                 :            :                                 tag::selected,
    2212                 :            :                                 tag::pdfpolicy > >,
    2213                 :            :              pdf_option< use< kw::pdf_centering >,
    2214                 :            :                          store< tk::ctr::PDFCentering,
    2215                 :            :                                 tag::selected,
    2216                 :            :                                 tag::pdfctr > >,
    2217                 :            :              pdf_option< use< kw::txt_float_format >,
    2218                 :            :                          store< tk::ctr::TxtFloatFormat,
    2219                 :            :                                 tag::flformat,
    2220                 :            :                                 tag::pdf > >,
    2221                 :            :              precision< use, tag::pdf >,
    2222                 :            :              parse_pdf > > {};
    2223                 :            : 
    2224                 :            :   //! \brief Ensure that a grammar only uses keywords from a pool of
    2225                 :            :   //!   pre-defined keywords
    2226                 :            :   //! \details In grammar definitions, every keyword should be wrapped around
    2227                 :            :   //!   this use template, which conditionally inherits the keyword type its
    2228                 :            :   //!   templated on (as defined in Control/Keywords.h) if the keyword is listed
    2229                 :            :   //!   in any of the pools of keywords passed in as the required pool template
    2230                 :            :   //!   argument and zero or more additional pools. If the keyword is not in any
    2231                 :            :   //!   of the pools, a compiler error is generated, since the struct cannot
    2232                 :            :   //!   inherit from base class 'char'. In that case, simply add the new keyword
    2233                 :            :   //!   into one of the pools of keywords corresponding to the given grammar.
    2234                 :            :   //!   The rationale behind this wrapper is to force the developer to maintain
    2235                 :            :   //!   the keywords pool for a grammar. The pools are brigand::set and are
    2236                 :            :   //!   used to provide help on command line arguments for a given executable.
    2237                 :            :   //!   They allow compile-time iteration with brigand::for_each or
    2238                 :            :   //!   generating a run-time std::map associating, e.g., keywords to their help
    2239                 :            :   //!   strings.
    2240                 :            :   //! \warning Note that an even more elegant solution to the problem this
    2241                 :            :   //!   wrapper is intended to solve is to use a metaprogram that collects all
    2242                 :            :   //!   occurrences of the keywords in a grammar. However, that does not seem to
    2243                 :            :   //!   be possible without extensive macro-trickery. Instead, if all keywords
    2244                 :            :   //!   in all grammar definitions are wrapped inside this use template (or one
    2245                 :            :   //!   of its specializations), we make sure that only those keywords can be
    2246                 :            :   //!   used by a grammar that are listed in the pool corresponding to a
    2247                 :            :   //!   grammar. However, this is still only a partial solution, since listing
    2248                 :            :   //!   more keywords in the pool than those used in the grammar is still
    2249                 :            :   //!   possible, which would result in those keywords included in, e.g., the
    2250                 :            :   //!   on-screen help generated even though some of the keywords may not be
    2251                 :            :   //!   implemented by the given grammar. So please don't abuse and don't list
    2252                 :            :   //!   keywords in the pool only if they are implemented in the grammar.
    2253                 :            :   //! \see For example usage see the template typedef
    2254                 :            :   //!   walker::cmd::use in Control/Walker/CmdLine/Grammar.h and its keywords
    2255                 :            :   //!   pool, walker::ctr::CmdLine::keywords, in
    2256                 :            :   //!   Control/Walker/CmdLine/CmdLine.h.
    2257                 :            :   //! \see http://en.cppreference.com/w/cpp/types/conditional
    2258                 :            :   //! TODO It still would be nice to generate a more developer-friendly
    2259                 :            :   //!    compiler error if the keyword is not in the pool.
    2260                 :            :   template< typename keyword, typename pool >
    2261                 :            :   struct use :
    2262                 :            :          std::conditional< brigand::or_<
    2263                 :            :                              brigand::has_key< pool, keyword > >::value,
    2264                 :            :                            keyword,
    2265                 :            :                            char >::type {};
    2266                 :            : 
    2267                 :            : } // grm::
    2268                 :            : } // tk::
    2269                 :            : 
    2270                 :            : #endif // CommonGrammar_h

Generated by: LCOV version 1.14