@@ -163,6 +163,12 @@ void LibertyAst::dump(FILE *f, sieve &blacklist, sieve &whitelist, std::string i
163
163
}
164
164
165
165
#ifndef FILTERLIB
166
+
167
+ // binary operators excluding ' '
168
+ bool LibertyExpression::is_nice_binop (char c) {
169
+ return c == ' *' || c == ' &' || c == ' ^' || c == ' +' || c == ' |' ;
170
+ }
171
+
166
172
// https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html
167
173
LibertyExpression LibertyExpression::parse (Lexer &s, int min_prio) {
168
174
if (s.empty ())
@@ -201,15 +207,8 @@ LibertyExpression LibertyExpression::parse(Lexer &s, int min_prio) {
201
207
while (true ) {
202
208
if (s.empty ())
203
209
break ;
204
-
205
- c = s.peek ();
206
210
207
- while (isspace (c)) {
208
- if (s.empty ())
209
- return lhs;
210
- s.next ();
211
- c = s.peek ();
212
- }
211
+ c = s.peek ();
213
212
214
213
if (c == ' \' ' ) { // postfix NOT
215
214
if (min_prio > 7 )
@@ -235,13 +234,31 @@ LibertyExpression LibertyExpression::parse(Lexer &s, int min_prio) {
235
234
lhs = std::move (n);
236
235
237
236
continue ;
238
- } else if (c == ' &' || c == ' *' ) { // infix AND
239
- // technically space should be considered infix AND. it seems rare in practice.
237
+ } else if (c == ' &' || c == ' *' || isspace (c)) { // infix AND
240
238
if (min_prio > 3 )
241
239
break ;
242
- s.next ();
240
+
241
+ if (isspace (c)) {
242
+ // Rewind past this space and any further spaces
243
+ while (isspace (c)) {
244
+ if (s.empty ())
245
+ return lhs;
246
+ s.next ();
247
+ c = s.peek ();
248
+ }
249
+ if (is_nice_binop (c)) {
250
+ // We found a real binop, so this space wasn't an AND
251
+ // and we just discard it as meaningless whitespace
252
+ continue ;
253
+ }
254
+ } else {
255
+ // Rewind past this op
256
+ s.next ();
257
+ }
243
258
244
259
auto rhs = parse (s, 4 );
260
+ if (rhs.kind == EMPTY)
261
+ continue ;
245
262
auto n = LibertyExpression{};
246
263
n.kind = Kind::AND;
247
264
n.children .push_back (lhs);
@@ -306,6 +323,45 @@ bool LibertyExpression::eval(dict<std::string, bool>& values) {
306
323
}
307
324
return false ;
308
325
}
326
+
327
+ std::string LibertyExpression::str (int indent)
328
+ {
329
+ std::string prefix;
330
+ switch (kind) {
331
+ case AND:
332
+ prefix += " (and " ;
333
+ break ;
334
+ case OR:
335
+ prefix += " (or " ;
336
+ break ;
337
+ case NOT:
338
+ prefix += " (not " ;
339
+ break ;
340
+ case XOR:
341
+ prefix += " (xor " ;
342
+ break ;
343
+ case PIN:
344
+ prefix += " (pin \" " + name + " \" " ;
345
+ break ;
346
+ case EMPTY:
347
+ prefix += " (" ;
348
+ break ;
349
+ default :
350
+ log_assert (false );
351
+ }
352
+ size_t add_indent = prefix.length ();
353
+ bool first = true ;
354
+ for (auto child : children) {
355
+ if (!first) {
356
+ prefix += " \n " + std::string (indent + add_indent, ' ' );
357
+ }
358
+ prefix += child.str (indent + add_indent);
359
+ first = false ;
360
+ }
361
+ prefix += " )" ;
362
+ return prefix;
363
+ }
364
+
309
365
#endif
310
366
311
367
int LibertyParser::lexer (std::string &str)
0 commit comments