From 7aa84975468a7098e572a0e692b625ab4660917c Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Wed, 25 Jul 2018 07:52:38 +0200
Subject: [PATCH] SongFilter: implement the AND operator

---
 doc/protocol.xml   |  7 +++++++
 src/SongFilter.cxx | 18 +++++++++++++++++-
 2 files changed, 24 insertions(+), 1 deletion(-)

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).
           </para>
         </listitem>
+
+        <listitem>
+          <para>
+            "<code>EXPRESSION1 AND EXPRESSION2 ...</code>": combine two or
+            more expressions with logical "and".
+          </para>
+        </listitem>
       </itemizedlist>
 
       <para>
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<AndSongFilter>();
+		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);