diff --git a/doc/protocol.xml b/doc/protocol.xml
index 23584b5f0..0b49cedab 100644
--- a/doc/protocol.xml
+++ b/doc/protocol.xml
@@ -268,6 +268,13 @@
time stamp).
+
+
+
+ "EXPRESSION1 AND EXPRESSION2 ...
": combine two or
+ more expressions with logical "and".
+
+
diff --git a/src/SongFilter.cxx b/src/SongFilter.cxx
index e9d609a5f..35a4b9865 100644
--- a/src/SongFilter.cxx
+++ b/src/SongFilter.cxx
@@ -334,7 +334,23 @@ SongFilter::ParseExpression(const char *&s, bool fold_case)
return first;
}
- throw std::runtime_error("Nested expressions not yet implemented");
+ if (ExpectWord(s) != "AND")
+ throw std::runtime_error("'AND' expected");
+
+ auto and_filter = std::make_unique();
+ and_filter->AddItem(std::move(first));
+
+ while (true) {
+ and_filter->AddItem(ParseExpression(s, fold_case));
+
+ if (*s == ')') {
+ ++s;
+ return and_filter;
+ }
+
+ if (ExpectWord(s) != "AND")
+ throw std::runtime_error("'AND' expected");
+ }
}
auto type = ExpectFilterType(s);