57 std::vector<QueryBuilderState>
states;
60 std::vector<InputSpec>
result;
61 char const* next = config;
62 char const* cur = config;
63 char const* expectedSeparators;
65 std::string errorString;
66 std::unique_ptr<DataDescriptorMatcher> currentMatcher;
67 std::vector<data_matcher::Node>
nodes;
68 std::optional<std::string> currentBinding;
69 std::optional<std::string> currentOrigin;
70 std::optional<std::string> currentDescription;
72 std::optional<std::string> currentValue;
73 std::optional<header::DataHeader::SubSpecificationType> currentSubSpec;
74 std::optional<uint64_t> currentTimeModulo;
75 Lifetime currentLifetime = Lifetime::Timeframe;
78 auto error = [&errorString, &
states](std::string
const& s) {
88 const char* modifier =
nullptr;
89 if (mod[0] !=
'\0' && (modifier = strpbrk(cur, mod)) !=
nullptr) {
95 error(
"invalid modifier '" + std::string(modifier, 1) +
"'");
105 expectedSeparators = sep;
108 auto assignLastStringMatch = [&next, &cur, &error, &pushState](std::string
const& what,
int maxSize, std::optional<std::string>& s,
QueryBuilderState nextState) {
109 if ((next - cur == 0) || (next - cur >
maxSize)) {
113 s = std::string(cur, next - cur);
114 if (memchr(
"\0;", *next, 2)) {
119 pushState(nextState);
124 auto assignLastNumericMatch = [&next, &cur, &error, &pushState, ¤tNumber](std::string
const&,
auto&
value,
126 if ((next - cur == 0)) {
127 error(
"number expected");
130 value = currentNumber;
131 if (memchr(
"\0;", *next, 2)) {
136 pushState(nextState);
141 std::vector<ConfigParamSpec> attributes;
143 auto buildMatchingTree = [&
nodes](std::string
const&
binding, std::vector<ConfigParamSpec> attributes) ->
InputSpec {
145 std::make_unique<DataDescriptorMatcher>(DataDescriptorMatcher::Op::Just,
147 for (
size_t ni = 0, ne =
nodes.size(); ni < ne; ++ni) {
149 auto tmp = std::make_unique<DataDescriptorMatcher>(DataDescriptorMatcher::Op::And,
151 std::move(lastMatcher));
152 assert(lastMatcher.get() ==
nullptr);
153 lastMatcher = std::move(tmp);
155 Lifetime lifetime = Lifetime::Timeframe;
156 for (
auto& attribute : attributes) {
157 if (attribute.name ==
"lifetime" && attribute.defaultValue.get<std::string>() ==
"condition") {
158 lifetime = Lifetime::Condition;
160 if (attribute.name ==
"lifetime" && attribute.defaultValue.get<std::string>() ==
"sporadic") {
161 lifetime = Lifetime::Sporadic;
167 auto pushMatcher = [&
nodes, &
states](
auto&& matcher) {
170 auto notMatcher = std::make_unique<DataDescriptorMatcher>(DataDescriptorMatcher::Op::Xor,
173 nodes.push_back(std::move(notMatcher));
175 nodes.push_back(std::move(matcher));
179 while (
states.empty() ==
false) {
185 next = strpbrk(cur, expectedSeparators);
186 if (next ==
nullptr) {
187 next = cur + strlen(cur);
191 currentNumber = strtoll(cur, &endptr, 0);
193 error(
"Expected a number");
205 currentBinding.reset();
206 currentOrigin.reset();
207 currentDescription.reset();
208 currentSubSpec.reset();
209 currentTimeModulo.reset();
219 if (memchr(
"\0/;", *next, 3)) {
223 if (next - cur == 0) {
224 error(
"empty binding string");
227 currentBinding = std::string(cur, next - cur);
238 }
else if (*next ==
';' && assignLastStringMatch(
"origin", 4, currentOrigin,
IN_END_MATCHER)) {
240 }
else if (*next ==
'?' && assignLastStringMatch(
"origin", 4, currentOrigin,
IN_BEGIN_ATTRIBUTES)) {
242 }
else if (*next ==
'\0' && assignLastStringMatch(
"origin", 4, currentOrigin,
IN_END_MATCHER)) {
245 error(
"origin needs to be between 1 and 4 char long");
253 if (*next ==
'/' && assignLastStringMatch(
"description", 16, currentDescription,
IN_BEGIN_SUBSPEC)) {
255 }
else if (*next ==
';' && assignLastStringMatch(
"description", 16, currentDescription,
IN_END_MATCHER)) {
257 }
else if (*next ==
'?' && assignLastStringMatch(
"description", 16, currentDescription,
IN_BEGIN_ATTRIBUTES)) {
259 }
else if (*next ==
'\0' && assignLastStringMatch(
"description", 16, currentDescription,
IN_END_MATCHER)) {
262 error(
"description needs to be between 1 and 16 char long");
270 if (*next ==
'%' && assignLastNumericMatch(
"subspec", currentSubSpec,
IN_BEGIN_TIMEMODULO)) {
271 }
else if (*next ==
'?' && assignLastNumericMatch(
"subspec", currentSubSpec,
IN_BEGIN_ATTRIBUTES)) {
272 }
else if (*next ==
';' && assignLastNumericMatch(
"subspec", currentSubSpec,
IN_END_MATCHER)) {
273 }
else if (*next ==
'\0' && assignLastNumericMatch(
"subspec", currentSubSpec,
IN_END_MATCHER)) {
275 error(
"Expected a number");
278 auto backup =
states.back();
288 assignLastNumericMatch(
"timemodulo", currentTimeModulo,
IN_ERROR);
291 if (*cur ==
';' && *(cur + 1) ==
'\0') {
292 error(
"Remove trailing ;");
296 result.push_back(buildMatchingTree(currentBinding.value_or(currentOrigin.value_or(
"")), attributes));
299 }
else if (*cur ==
';') {
303 error(
"Unexpected character " + std::string(cur, 1));
317 error(
"missing value for attribute key");
326 assignLastStringMatch(
"value", 1000, currentValue,
IN_BEGIN_KEY);
327 if (*
currentKey ==
"lifetime" && currentValue ==
"condition") {
328 currentLifetime = Lifetime::Condition;
331 int val = currentValue ==
"false" ? 0 : (currentValue ==
"true" ? 1 : std::stoi(*currentValue));
336 }
else if (*next ==
';') {
338 if (*
currentKey ==
"lifetime" && currentValue ==
"condition") {
339 currentLifetime = Lifetime::Condition;
342 int val = currentValue ==
"false" ? 0 : (currentValue ==
"true" ? 1 : std::stoi(*currentValue));
347 }
else if (*next ==
'\0') {
349 if (*
currentKey ==
"lifetime" && currentValue ==
"condition") {
350 currentLifetime = Lifetime::Condition;
353 int val = currentValue ==
"false" ? 0 : (currentValue ==
"true" ? 1 : std::stoi(*currentValue));
359 error(
"missing value for string value");
366 error(
"property modifiers should have been handled before when inserting previous matcher");
369 throw std::runtime_error(
"Parse error: " + errorString);
374 error(
"Unhandled state");