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 [ - - ]: 0 : 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 [ - - ]: 0 : 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 [ - - ][ - - ]: 0 : std::string("Unknown parser ") +
545 [ - - ]: 0 : (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 : 9139 : 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 : 9139 : }
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 : 70 : static void store_option( Stack& stack,
604 : : const Input& in,
605 : : const DefaultStack& defaults ) {
606 [ + - ]: 140 : Option opt;
607 [ + - ]: 140 : auto value = in.string();
608 [ + - ][ + - ]: 70 : if (opt.exist(value)) {
609 [ + - ]: 70 : 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 [ + - ][ + + ]: 93 : if (stack.template get< tags... >() != opt.value( value ) &&
[ - + ]
619 [ - + ]: 23 : stack.template get< tags... >() != defaults.template get< tags... >())
620 : : g_print << "\n>>> WARNING: Multiple definitions for '"
621 : 0 : << opt.group() << "' option. Overwriting '"
622 [ - - ]: 0 : << opt.name( stack.template get< tags... >() ) << "' with '"
623 [ - - ]: 0 : << opt.name( opt.value( value ) ) << "' at "
624 [ - - ][ - - ]: 0 : << pos.line << ',' << pos.byte_in_line << ".\n\n";
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
625 [ + - ]: 70 : stack.template get< tags... >() = opt.value( value );
626 : : } else {
627 [ - - ]: 0 : 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 [ + - ]: 70 : brigand::for_each< typename Option::keywords >( is_keyword< use >() );
632 : 70 : }
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 : 10154 : static void apply( const Input& in, State& state ) {
649 : : using swallow = bool[];
650 : 10154 : (void)swallow{ ( action< As >::apply( in, state ), true )..., true };
651 : 10154 : }
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 : 0 : static void apply( const Input& in, Stack& stack ) {
676 : 0 : Message< Stack, type, key >( stack, in );
677 : 0 : }
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 : 97 : static void apply( const Input& in, Stack& stack ) {
690 : 97 : stack.template get< tag, tags... >() = in.string();
691 : 97 : }
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 : 552 : static void apply( const Input& in, Stack& stack ) {
704 [ + - ]: 552 : if (!in.string().empty())
705 : 552 : stack.template store< tag, tags... >( in.string() );
706 : : else
707 : 0 : Message< Stack, ERROR, MsgKey::MISSING >( stack, in );
708 : 552 : }
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 : 215 : static void apply( const Input& in, Stack& stack ) {
722 : 215 : stack.template store_back< tag, tags... >( in.string() );
723 : 215 : }
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 : 917 : static void apply( const Input& in, Stack& stack ) {
754 : 917 : stack.template store_back_back< tag, tags... >( in.string() );
755 : 917 : }
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 : 270 : static void apply( const Input& in, Stack& stack ) {
770 : 270 : stack.template store_back_back_back< tag, tags... >( in.string() );
771 : 270 : }
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 : 195 : static void apply( const Input&, Stack& stack ) {
881 : 195 : stack.template get< tags... >() = !stack.template get< tags... >();
882 : 195 : }
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 : 548 : static void apply( const Input& in, Stack& stack ) {
903 [ + - ]: 1096 : Option opt;
904 [ + - ][ + - ]: 548 : if (opt.exist(in.string())) {
[ + - ]
905 [ + - ][ + - ]: 548 : stack.template get<tag,tags...>().push_back( opt.value( in.string() ) );
[ + - ]
906 : : } else {
907 [ - - ]: 0 : 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 [ + - ]: 548 : brigand::for_each< typename Option::keywords >( is_keyword< use >() );
912 : 548 : }
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 : 50 : static void apply( const Input& in, Stack& stack ) {
936 [ + - ]: 100 : Option opt;
937 [ + - ][ + - ]: 50 : if (opt.exist(in.string())) {
[ + - ]
938 : 50 : stack.template get<tag,tags...>().back().
939 [ + - ][ + - ]: 50 : push_back( opt.value( in.string() ) );
[ + - ]
940 : : } else {
941 [ - - ]: 0 : 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 [ + - ]: 50 : brigand::for_each< typename Option::keywords >( is_keyword< use >() );
946 : 50 : }
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 : 22 : static void apply( const Input& in, Stack& stack ) {
1078 : : // get recently inserted key from < sel, vec >
1079 : 22 : 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 [ + - ]: 22 : ( key, in.string() );
1083 : 22 : }
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 : 0 : static void apply( const Input& in, Stack& stack ) {
1103 : : // get recently inserted key from <sel,vec>
1104 : 0 : const auto& key = stack.template get< sel, vec >().back();
1105 : : stack.template
1106 : : insert_field< field, typename Option::EnumType, tag, tags... >
1107 [ - - ][ - - ]: 0 : ( 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 : 0 : brigand::for_each< typename Option::keywords >( is_keyword< use >() );
1111 : 0 : }
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 : 26 : static void apply( const Input& in, Stack& stack ) {
1126 : : using PrEx = kw::precision::info::expect;
1127 [ + - ]: 52 : std::string low( in.string() );
1128 : 26 : std::transform( begin(low), end(low), begin(low), ::tolower );
1129 [ - + ]: 26 : if (low == "max") {
1130 : 0 : const auto maxprec = PrEx::upper;
1131 : 0 : stack.template get< tag::prec, prec >() = maxprec;
1132 : : } else {
1133 : 26 : PrEx::type precision = std::cout.precision(); // set default
1134 : : try { //try to convert matched str to int
1135 [ + - ][ + - ]: 26 : precision = std::stol( in.string() );
1136 : : }
1137 [ - - ]: 0 : catch ( std::exception& ) {
1138 [ - - ]: 0 : Message< Stack, ERROR, MsgKey::BADPRECISION >( stack, in );
1139 : : }
1140 : : // only set precision given if it makes sense
1141 [ + - ][ + - ]: 26 : if (precision >= PrEx::lower && precision <= PrEx::upper)
1142 : 26 : stack.template get< tag::prec, prec >() = precision;
1143 : : else
1144 [ - - ]: 0 : Message< Stack, WARNING, MsgKey::PRECISIONBOUNDS >( stack, in );
1145 : : }
1146 : 26 : }
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 : 0 : const auto& cmdinfo = stack.template get< tag::cmdinfo >();
1167 : 0 : 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 : 2799 : static void apply( const Input& in, Stack& stack ) {
1192 : : // convert matched string to char
1193 [ + - ][ + - ]: 2799 : auto var = stack.template convert< char >( in.string() );
1194 : : // find matched variable in set of selected ones
1195 [ + - ][ + - ]: 2799 : if (depvars.find( var ) != depvars.end())
1196 [ + - ]: 2799 : action< push >::apply( in, stack );
1197 : : else // error out if matched var is not selected
1198 [ - - ]: 0 : Message< Stack, ERROR, MsgKey::NOSUCHDEPVAR >( stack, in );
1199 : 2799 : }
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 : 29 : static void apply( const Input& in, Stack& stack ) {
1211 : : // find matched name in set of registered ones
1212 [ + - ][ + - ]: 29 : if (pdfnames.find( in.string() ) == pdfnames.end()) {
[ + - ]
1213 [ + - ]: 29 : pdfnames.insert( in.string() );
1214 : 29 : stack.template get< tag::cmd, tag::io, tag::pdfnames >().
1215 [ + - ]: 29 : push_back( in.string() );
1216 : : }
1217 : : else // error out if name matched var is already registered
1218 : 0 : Message< Stack, ERROR, MsgKey::PDFEXISTS >( stack, in );
1219 : 29 : }
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 : 99 : static void apply( const Input& in, Stack& stack ) {
1232 : : // error out if chosen item does not exist in selected vector
1233 : 99 : bool exists = false;
1234 [ + + ]: 210 : for (const auto& r : stack.template get< sel, vec >()) {
1235 : : // cppcheck-suppress useStlAlgorithm
1236 [ + - ][ + - ]: 111 : if (Option().value(in.string()) == r) exists = true;
[ + - ][ + - ]
1237 : : }
1238 [ + - ]: 99 : if (exists)
1239 : 99 : action< store_back_option< use, Option, tags... > >::apply( in, stack );
1240 : : else
1241 : 0 : Message< Stack, ERROR, MsgKey::NOTSELECTED >( stack, in );
1242 : 99 : }
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 : 105 : static void apply( const Input& in, Stack& stack ) {
1252 : : // convert matched string to char
1253 [ + - ][ + - ]: 105 : auto newvar = stack.template convert< char >( in.string() );
1254 : : // put in new dependent variable to set of already selected ones
1255 [ + - ][ + - ]: 105 : if (depvars.find( newvar ) == depvars.end())
1256 [ + - ]: 105 : depvars.insert( newvar );
1257 : : else // error out if depvar is already taken
1258 [ - - ]: 0 : Message< Stack, ERROR, MsgKey::EXISTS >( stack, in );
1259 : 105 : }
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 : 455 : static void apply( const Input& in, Stack& stack ) {
1270 : 455 : auto lower = keyword::info::expect::lower;
1271 : 455 : auto val = stack.template get< tag, tags... >();
1272 [ - + ]: 455 : if (val < lower) Message< Stack, ERROR, MsgKey::BOUNDS >( stack, in );
1273 : 455 : }
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 : 19 : static void apply( const Input& in, Stack& stack ) {
1284 : 19 : auto upper = keyword::info::expect::upper;
1285 : 19 : auto val = stack.template get< tag, tags... >();
1286 [ - + ]: 19 : if (val > upper) Message< Stack, ERROR, MsgKey::BOUNDS >( stack, in );
1287 : 19 : }
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 : 2097 : static void apply( const Input&, Stack& stack ) {
1298 : 2097 : stack.template get< tag, tags... >().emplace_back();
1299 : 2097 : }
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 : 90 : static void apply( const Input&, Stack& stack ) {
1310 : : // no arg: use default ctor
1311 : 90 : stack.template get< tag, tags... >().back().emplace_back();
1312 : 90 : }
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 : 2752 : static void apply( const Input& in, Stack& stack ) {
1336 : : // If var is given, push var, otherwise push first char of value
1337 [ + - ]: 2752 : char v(var ? var : in.string()[0]);
1338 : : // Use a shorthand of reference to vector to push_back to
1339 : 2752 : auto& stats = stack.template get< tag::stat >();
1340 : : // Push term into current vector
1341 [ + - ]: 2752 : 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 : 1851 : tk::ctr::Term term( static_cast<char>(toupper(v)),
1345 : : field,
1346 : : tk::ctr::Moment::ORDINARY );
1347 [ + - ][ + - ]: 1851 : stats.insert( stats.end()-1, tk::ctr::Product( 1, term ) );
1348 : : }
1349 : 2752 : field = 0; // reset default field
1350 : 2752 : }
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 : 47 : static void apply( const Input& in, Stack& stack ) {
1360 : : // Use a shorthand of reference to vector to push_back to
1361 : 47 : auto& pdf = stack.template get< tag::pdf >();
1362 : : // Error out if sample space already has at least 3 dimensions
1363 [ - + ]: 47 : if ( pdf.back().size() >= 3 ) {
1364 : 0 : Message< Stack, ERROR, MsgKey::MAXSAMPLES >( stack, in );
1365 : : }
1366 : : // Error out if matched sample space variable starts with a digit
1367 [ + - ][ - + ]: 47 : if ( std::isdigit(in.string()[0]) )
1368 : 0 : Message< Stack, ERROR, MsgKey::MALFORMEDSAMPLE >( stack, in );
1369 : : // Push term into current vector
1370 [ + - ][ + - ]: 47 : 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 [ + - ][ + - ]: 20 : tk::ctr::Term term( static_cast<char>(toupper(in.string()[0])),
1374 : : field,
1375 : : tk::ctr::Moment::ORDINARY );
1376 : 20 : auto& stats = stack.template get< tag::stat >();
1377 [ + + ]: 20 : if (!stats.empty())
1378 [ + - ][ + - ]: 14 : stats.insert( stats.end()-1, tk::ctr::Product( 1, term ) );
1379 : : else
1380 [ + - ][ + - ]: 6 : stats.emplace_back( tk::ctr::Product( 1, term ) );
1381 : : }
1382 : 47 : field = 0; // reset default field
1383 : 47 : }
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 : 47 : static void apply( const Input& in, Stack& stack ) {
1393 : : // Use a shorthand of reference to vector to push_back to
1394 : 47 : auto& bins = stack.template get< tag::discr, tag::binsize >().back();
1395 : : // Error out if binsize vector already has at least 3 dimensions
1396 [ - + ]: 47 : if ( bins.size() >= 3 ) {
1397 : 0 : Message< Stack, ERROR, MsgKey::MAXBINSIZES >( stack, in );
1398 : : }
1399 : : // Push term into vector if larger than zero
1400 [ + - ]: 47 : const auto& binsize = stack.template convert< tk::real >( in.string() );
1401 [ - + ]: 47 : if ( !(binsize > std::numeric_limits< tk::real >::epsilon()) )
1402 : 0 : Message< Stack, ERROR, MsgKey::ZEROBINSIZE >( stack, in );
1403 : : else
1404 : 47 : bins.emplace_back( binsize );
1405 : 47 : }
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 : 62 : static void apply( const Input& in, Stack& stack ) {
1415 : : // Use a shorthand of reference to vector to push_back to
1416 : 62 : auto& vec = stack.template get< tag::discr, tag::extent >().back();
1417 : : // Error out if extents vector already has at least 3 pairs
1418 [ - + ]: 62 : if (vec.size() >= 6)
1419 : 0 : 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 : 62 : if (vec.size() >=
1423 [ - + ]: 62 : stack.template get< tag::discr, tag::binsize >().back().size() * 2) {
1424 : 0 : Message< Stack, ERROR, MsgKey::INVALIDEXTENT >( stack, in );
1425 : : }
1426 : : // Push extent into vector
1427 [ + - ][ + - ]: 62 : vec.emplace_back( stack.template convert< tk::real >( in.string() ) );
1428 : 62 : }
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 : 296 : 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 : 20 : static void apply( const Input& in, Stack& stack ) {
1460 : : const auto& spike =
1461 : 20 : stack.template get< tag::param, eq, param, xparam... >().back().back();
1462 : : // Error out if the number of spikes-vector is odd
1463 [ - + ]: 20 : if (spike.size() % 2)
1464 : 0 : 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 [ + - ]: 20 : if (!spike.empty()) {
1470 : 20 : tk::real sum = 0.0;
1471 [ + + ]: 60 : for (std::size_t i=1; i<spike.size(); i+=2) // every even is a height
1472 : 40 : sum += spike[i];
1473 [ - + ]: 20 : if (std::abs(sum-1.0) > std::numeric_limits< tk::real >::epsilon())
1474 : 0 : Message< Stack, ERROR, MsgKey::HEIGHTSPIKES >( stack, in );
1475 : : }
1476 : 20 : }
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 : 25 : static void apply( const Input& in, Stack& stack ) {
1489 : : const auto& betapdf =
1490 : 25 : stack.template get< tag::param, eq, param, xparam... >().back().back();
1491 : : // Error out if the number parameters is not four
1492 [ - + ]: 25 : if (betapdf.size() != 4)
1493 : 0 : Message< Stack, ERROR, MsgKey::WRONGBETAPDF >( stack, in );
1494 : 25 : }
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 : 6 : static void apply( const Input& in, Stack& stack ) {
1507 : : const auto& gamma =
1508 : 6 : stack.template get< tag::param, eq, param, xparam... >().back().back();
1509 : : // Error out if the number parameters is not two
1510 [ - + ]: 6 : if (gamma.size() != 2)
1511 : 0 : Message< Stack, ERROR, MsgKey::WRONGGAMMAPDF >( stack, in );
1512 : : // Error out if the specified shape or scale parameter negative
1513 [ + - ][ - + ]: 6 : if (gamma[0] < 0.0 || gamma[1] < 0.0)
[ - + ]
1514 : 0 : Message< Stack, ERROR, MsgKey::NEGATIVEPARAM >( stack, in );
1515 : 6 : }
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 : 8 : static void apply( const Input& in, Stack& stack ) {
1528 : : const auto& dir =
1529 : 8 : stack.template get< tag::param, eq, param, xparam... >().back();
1530 : : // get recently configured eq block number of scalar components
1531 : 8 : auto ncomp =
1532 : 8 : stack.template get< tag::component >().template get< eq >().back();
1533 : : // Error out if the number parameters does not equal ncomp
1534 [ - + ]: 8 : if (dir.size() != ncomp-2)
1535 : 0 : Message< Stack, ERROR, MsgKey::WRONGDIRICHLET >( stack, in );
1536 : : // Error out if the specified shape or scale parameter negative
1537 [ + + ]: 32 : for (auto a : dir)
1538 [ - + ]: 24 : if (a < 0.0)
1539 [ - - ]: 0 : Message< Stack, ERROR, MsgKey::NEGATIVEPARAM >( stack, in );
1540 : 8 : }
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 : 39 : static void apply( const Input& in, Stack& stack ) {
1553 : : const auto& gaussian =
1554 : 39 : stack.template get< tag::param, eq, param, xparam... >().back().back();
1555 : : // Error out if the number parameters is not two
1556 [ - + ]: 39 : if (gaussian.size() != 2)
1557 : 0 : Message< Stack, ERROR, MsgKey::WRONGGAUSSIAN >( stack, in );
1558 : : // Error out if the specified variance is negative
1559 [ - + ]: 39 : if (gaussian.back() < 0.0)
1560 : 0 : Message< Stack, ERROR, MsgKey::NEGATIVEPARAM >( stack, in );
1561 : 39 : }
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 : 1276 : static void apply( const Input& in, Stack& stack ) {
1571 [ - + ]: 1276 : if (stack.template get< tag::stat >().back().empty())
1572 : 0 : Message< Stack, ERROR, MsgKey::NOTERMS >( stack, in );
1573 : 1276 : }
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 : 29 : static void apply( const Input& in, Stack& stack ) {
1583 [ - + ]: 58 : if (stack.template get< tag::pdf >().back().size() !=
1584 : 29 : stack.template get< tag::discr, tag::binsize >().back().size())
1585 : 0 : Message< Stack, ERROR, MsgKey::BINSIZES >( stack, in );
1586 : 29 : }
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 : 29 : static void apply( const Input& in, Stack& stack ) {
1596 : : // Use a shorthand to extents vector
1597 : 29 : const auto& e = stack.template get< tag::discr, tag::extent >().back();
1598 : : // Check if the number of extents are correct
1599 [ + + ][ - + ]: 52 : if (!e.empty() &&
1600 : 23 : e.size() !=
1601 [ - + ]: 23 : stack.template get< tag::discr, tag::binsize >().back().size()*2)
1602 : 0 : Message< Stack, ERROR, MsgKey::INVALIDEXTENT >( stack, in );
1603 : : // Check if the lower extents are indeed lower than the higher extents
1604 [ + + ][ - + ]: 29 : if (e.size() > 1 && e[0] > e[1])
[ - + ]
1605 : 0 : Message< Stack, ERROR, MsgKey::EXTENTLOWER >( stack, in );
1606 [ + + ][ - + ]: 29 : if (e.size() > 3 && e[2] > e[3])
[ - + ]
1607 : 0 : Message< Stack, ERROR, MsgKey::EXTENTLOWER >( stack, in );
1608 [ + + ][ - + ]: 29 : if (e.size() > 5 && e[4] > e[5])
[ - + ]
1609 : 0 : Message< Stack, ERROR, MsgKey::EXTENTLOWER >( stack, in );
1610 : 29 : }
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 : 29 : static void apply( const Input& in, Stack& stack ) {
1620 [ - + ]: 29 : if (stack.template get< tag::pdf >().back().empty())
1621 : 0 : Message< Stack, ERROR, MsgKey::NOSAMPLES >( stack, in );
1622 : 29 : }
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 : 2769 : static void apply( const Input& in, Stack& stack ) {
1632 : : // field ID numbers start at 0
1633 [ + - ]: 2769 : auto f = stack.template convert< long >( in.string() ) - 1;
1634 [ - + ]: 2769 : if (f < 0)
1635 : 0 : Message< Stack, ERROR, MsgKey::POSITIVECOMPONENT >( stack, in );
1636 : 2769 : field = static_cast< ncomp_t >( f );
1637 : 2769 : }
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
|