24{
25 using namespace peg;
26 parser parser(R"(
27 Reactions <- (_ Reaction _ Newline?)* _
28 Reaction <- TermList _ '->' _ TermList _ Metadata?
29 TermList <- Term (_ Term)*
30 Term <- Coefficient? Species
31 Coefficient <- Float
32 Float <- [+-]? (_)? ([0-9]+)? ('.' [0-9]+)?
33 Species <- BaseSpecies State? Charge?
34 BaseSpecies <- [a-zA-Z][a-zA-Z0-9_]*
35 State <- '(' [a-z]{1,3} ')'
36 Charge <- ('^'? [0-9]* [+-])
37 Metadata <- '[' _ Pair (_ ',' _ Pair)* _ ']'
38 Pair <- Key _ '=' _ Value
39 Key <- [A-Za-z_][A-Za-z0-9_]*
40 Value <- [A-Za-z0-9_.-]+
41 Newline <- [\r\n]+
42 ~_ <- [ \t]*
43 )");
44 mooseAssert(parser, "Failed to build parser");
45
46
47 parser["Reactions"] = [](const SemanticValues & vs)
48 {
49 std::vector<Reaction> reactions;
50 for (
const auto &
v : vs)
51 {
53 {
54 reactions.push_back(std::any_cast<Reaction>(
v));
55 }
56 }
57 return reactions;
58 };
59
60 parser["Float"] = [](const SemanticValues & vs)
61 {
62
63 std::string vs_str = std::string(std::any_cast<std::string_view>(vs.token()));
64 vs_str.erase(std::remove(vs_str.begin(), vs_str.end(), ' '), vs_str.end());
65 if (vs_str == "-")
66 return -1.;
67 else if (vs_str == "+" || vs_str == "")
68 return 1.;
69 else
70 return std::stod(std::string(vs_str));
71 };
72
73 parser["Coefficient"] = [](const SemanticValues & vs) { return std::any_cast<double>(vs[0]); };
74
75 parser["BaseSpecies"] = [](const SemanticValues & vs) { return vs.token(); };
76
77 parser["State"] = [](const SemanticValues & vs) { return vs.token(); };
78
79 parser["Charge"] = [](const SemanticValues & vs) { return vs.token(); };
80
81 parser["Species"] = [](const SemanticValues & vs)
82 {
83 std::string base = std::string(std::any_cast<std::string_view>(vs[0]));
84 std::optional<std::string> state;
85 std::optional<std::string> charge;
86
87
88 if (vs.size() >= 2)
89 {
90 for (size_t i = 1; i < vs.size(); ++i)
91 if (vs[i].type() == typeid(std::string_view))
92 {
93 std::string val = std::string(std::any_cast<std::string_view>(vs[i]));
94 if (val.front() == '(' && val.back() == ')')
95 state = val;
96 else
97 charge = val;
98 }
99 }
100
101 return Term{1.0, base, state, charge};
102 };
103
104 parser["Term"] = [](const SemanticValues & vs)
105 {
106 mooseAssert(vs.size() <= 2, "Should only have a coefficient and a species");
107 if (vs.size() == 2)
108 {
109 double coeff = std::any_cast<double>(vs[0]);
110 Term term = std::any_cast<Term>(vs[1]);
111 term.coefficient = coeff;
112 return term;
113 }
114 else
115 return std::any_cast<Term>(vs[0]);
116 };
117
118 parser["TermList"] = [](const SemanticValues & vs)
119 {
121 for (
const auto &
v : vs)
122 {
123
124 if (
v.type() ==
typeid(Term))
125 terms.push_back(std::any_cast<Term>(
v));
126
127 else if (
v.type() ==
typeid(std::vector<Term>))
128 {
129 const auto & more = std::any_cast<std::vector<Term>>(
v);
130 terms.insert(terms.end(), more.begin(), more.end());
131 }
132 }
133 return terms;
134 };
135
136
137 parser["Key"] = [](const SemanticValues & vs) { return vs.token(); };
138
139 parser["Value"] = [](const SemanticValues & vs) { return vs.token(); };
140
141 parser["Pair"] = [](const SemanticValues & vs)
142 {
143 mooseAssert(vs.size() == 2, "Metadata entry should have exactly one key and one value");
144 return std::make_pair(std::string(std::any_cast<std::string_view>(vs[0])),
145 std::string(std::any_cast<std::string_view>(vs[1])));
146 };
147
148 parser["Metadata"] = [](const SemanticValues & vs)
149 {
151 for (
const auto &
v : vs)
152 {
153 if (
v.type() ==
typeid(std::pair<std::string, std::string>))
154 {
155 const auto & [k, val] = std::any_cast<std::pair<std::string, std::string>>(
v);
156 meta[k] = val;
157 }
158 else if (
v.type() ==
typeid(std::vector<std::pair<std::string, std::string>>))
159 {
160 const auto & pairs = std::any_cast<std::vector<std::pair<std::string, std::string>>>(
v);
161 for (const auto & [k, val] : pairs)
162 meta[k] = val;
163 }
164 }
165 return meta;
166 };
167
168 parser["Reaction"] = [](const SemanticValues & vs)
169 {
171 if (vs.size() != 2 && vs.size() != 3)
172 mooseError(
"Reaction failed to read as 'reactors -> products [metadata]");
173 r.reactants = std::any_cast<TermList>(vs[0]);
174 r.products = std::any_cast<TermList>(vs[1]);
175 if (vs.size() == 3)
176 r.metadata = std::any_cast<Metadata>(vs[2]);
177 return r;
178 };
179
180 parser.enable_packrat_parsing();
181
182 std::vector<Reaction> reactions;
183 if (!parser.parse(reaction_network_string, reactions))
185
186
187 if (output_to_cout)
188 {
189 for (size_t i = 0; i < reactions.size(); ++i)
190 {
191 const auto & r = reactions[i];
192 Moose::out << "Reaction " << i + 1 << ":\n";
194 }
195 }
196
197 return reactions;
198}
void mooseError(Args &&... args)
std::string stringify(const T &t)
std::vector< Term > TermList
std::map< std::string, std::string > Metadata