Wrapping of extension queries
diff --git a/CHANGES b/CHANGES
index 7cf9e58..7d7cc59 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,8 @@
+0.46 2014-10-21
+        - [feature] Support for relation queries (margaretha)
+	- [feature] Wrapping of extension queries
+	  (not completely tested yet; diewald)
+
 0.45 2014-10-06
         - [bugfix] Correctly respond request in JSON results (diewald)
         - [cleanup] Made SpanQueryWrapper an abstract class instead
diff --git a/pom.xml b/pom.xml
index efbf00e..e94e090 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,7 +24,7 @@
 
   <groupId>KorAP-modules</groupId>
   <artifactId>KorAP-lucene-index</artifactId>
-  <version>0.45</version>
+  <version>0.46</version>
   <packaging>jar</packaging>
 
   <name>KorAP-lucene-index</name>
diff --git a/src/main/java/de/ids_mannheim/korap/KorapQuery.java b/src/main/java/de/ids_mannheim/korap/KorapQuery.java
index f07ce51..e15eeef 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapQuery.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapQuery.java
@@ -329,9 +329,14 @@
 
 		    if (number > MAX_CLASS_NUM)
 			throw new QueryException("Class numbers limited to " + MAX_CLASS_NUM);
-		    return new SpanClassQueryWrapper(
-		      this.fromJSON(operands.get(0)), number
-                    );
+
+		    SpanQueryWrapper sqw = this.fromJSON(operands.get(0));
+
+		    // Problematic
+		    if (sqw.maybeExtension())
+			return sqw.setClassNumber(number);
+
+		    return new SpanClassQueryWrapper(sqw, number);
 		};
 
 		throw new QueryException("Class group expects class attribute");
@@ -340,6 +345,7 @@
 
 		int min = 0;
 		int max = 100;
+
 		if (json.has("boundary")) {
 		    Boundary b = new Boundary(json.get("boundary"), 0, 100);
 		    min = b.min;
@@ -374,10 +380,12 @@
 		if (min > max)
 		    max = max;
 
-		// This may be an empty repetitor
-		return new SpanRepetitionQueryWrapper(
-		    this.fromJSON(operands.get(0)), min, max
-		);
+		SpanQueryWrapper sqw = this.fromJSON(operands.get(0));
+
+		if (sqw.maybeExtension())
+		    return sqw.setMin(min).setMax(max);
+
+		return new SpanRepetitionQueryWrapper(sqw, min, max);
 	    };
 
 	    throw new QueryException("Unknown group operation");
@@ -422,8 +430,9 @@
 
 	case "korap:token":
 
+	    // The token is empty and should be treated like []
 	    if (!json.has("wrap"))
-		return new SpanEmptyTokenWrapper();
+		return new SpanRepetitionQueryWrapper();
 
 	    return this._segFromJSON(json.get("wrap"));
 
diff --git a/src/main/java/de/ids_mannheim/korap/KorapSearch.java b/src/main/java/de/ids_mannheim/korap/KorapSearch.java
index bdb059d..223ea72 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapSearch.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapSearch.java
@@ -54,14 +54,19 @@
 	    // "query" value
 	    if (this.request.has("query")) {
 		try {
-		    SpanQueryWrapper queryIface = new KorapQuery("tokens").fromJSON(this.request.get("query"));
-		    
-		    this.query = queryIface.toQuery();
-		    if (queryIface.isOptional())
-			this.addWarning("Optionality of query is ignored");
-		    if (queryIface.isNegative())
-			this.addWarning("Exclusivity of query is ignored");
+		    SpanQueryWrapper qw = new KorapQuery("tokens").fromJSON(this.request.get("query"));
 
+		    if (qw.isEmpty()) {
+			this.error = "This query matches everywhere";
+		    }
+		    else {
+		    
+			this.query = qw.toQuery();
+			if (qw.isOptional())
+			    this.addWarning("Optionality of query is ignored");
+			if (qw.isNegative())
+			    this.addWarning("Exclusivity of query is ignored");
+		    };
 		}
 		catch (QueryException q) {
 		    this.error = q.getMessage();
@@ -117,7 +122,12 @@
 
     // Maybe accept queryWrapperStuff
     public KorapSearch (SpanQueryWrapper sqwi) {
-	this.query = sqwi.toQuery();
+	try {
+	    this.query = sqwi.toQuery();
+	}
+	catch (QueryException q) {
+	    this.error = q.getMessage();
+	};
     };
 
     public KorapSearch (SpanQuery sq) {
@@ -151,7 +161,12 @@
     };
 
     public KorapSearch setQuery (SpanQueryWrapper sqwi) {
-	this.query = sqwi.toQuery();
+	try {
+	    this.query = sqwi.toQuery();
+	}
+	catch (QueryException q) {
+	    this.error = q.getMessage();
+	};
 	return this;
     };
 
diff --git a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanAlterQueryWrapper.java b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanAlterQueryWrapper.java
index 2a04554..809a325 100644
--- a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanAlterQueryWrapper.java
+++ b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanAlterQueryWrapper.java
@@ -3,8 +3,11 @@
 import de.ids_mannheim.korap.query.wrap.SpanRegexQueryWrapper;
 import de.ids_mannheim.korap.query.wrap.SpanWildcardQueryWrapper;
 import de.ids_mannheim.korap.query.wrap.SpanSegmentQueryWrapper;
+import de.ids_mannheim.korap.query.wrap.SpanSimpleQueryWrapper;
 import de.ids_mannheim.korap.query.wrap.SpanQueryWrapper;
 
+import de.ids_mannheim.korap.util.QueryException;
+
 import org.apache.lucene.search.spans.SpanQuery;
 import org.apache.lucene.search.spans.SpanTermQuery;
 import org.apache.lucene.search.spans.SpanOrQuery;
@@ -15,7 +18,7 @@
 public class SpanAlterQueryWrapper extends SpanQueryWrapper {
     private String field;
     private SpanQuery query;
-    private List<SpanQuery> alternatives;
+    private List<SpanQueryWrapper> alternatives;
 
     public SpanAlterQueryWrapper (String field) {
 	this.field = field;
@@ -25,6 +28,14 @@
     public SpanAlterQueryWrapper (String field, SpanQuery query) {
 	this.field = field;
 	this.alternatives = new ArrayList<>();
+	this.alternatives.add(
+            new SpanSimpleQueryWrapper(query)
+        );
+    };
+
+    public SpanAlterQueryWrapper (String field, SpanQueryWrapper query) {
+	this.field = field;
+	this.alternatives = new ArrayList<>();
 	this.alternatives.add(query);
     };
 
@@ -33,16 +44,26 @@
 	this.alternatives = new ArrayList<>();
 	for (String term : terms) {
 	    this.isNull = false;
-	    this.alternatives.add(new SpanTermQuery(new Term(this.field, term)));
+	    this.alternatives.add(
+	        new SpanSimpleQueryWrapper(
+                    new SpanTermQuery(
+                        new Term(this.field, term)
+		    )
+                )
+            );
 	};
     };
 
     public SpanAlterQueryWrapper or (String term) {
-	return this.or(new SpanTermQuery(new Term(this.field, term)));
+	return this.or(
+          new SpanTermQuery(new Term(this.field, term))
+        );
     };
 
     public SpanAlterQueryWrapper or (SpanQuery query) {
-	this.alternatives.add(query);
+	this.alternatives.add(
+            new SpanSimpleQueryWrapper(query)
+	);
 	this.isNull = false;
 	return this;
     };
@@ -59,35 +80,35 @@
 	if (term.isOptional())
 	    this.isOptional = true;
 
-	this.alternatives.add( term.toQuery() );
+	this.alternatives.add( term );
 	this.isNull = false;
 	return this;
     };
 
     public SpanAlterQueryWrapper or (SpanRegexQueryWrapper term) {
-	this.alternatives.add( term.toQuery() );
+	this.alternatives.add( term );
 	this.isNull = false;
 	return this;
     };
 
     public SpanAlterQueryWrapper or (SpanWildcardQueryWrapper wc) {
-	this.alternatives.add( wc.toQuery() );
+	this.alternatives.add( wc );
 	this.isNull = false;
 	return this;
     };
 
-    public SpanQuery toQuery() {
+    public SpanQuery toQuery() throws QueryException {
 	if (this.isNull || this.alternatives.size() == 0)
 	    return (SpanQuery) null;
 	    
 	if (this.alternatives.size() == 1) {
-	    return (SpanQuery) this.alternatives.get(0);
+	    return (SpanQuery) this.alternatives.get(0).toQuery();
 	};
 
-	Iterator<SpanQuery> clause = this.alternatives.iterator();
-	SpanOrQuery soquery = new SpanOrQuery( clause.next() );
+	Iterator<SpanQueryWrapper> clause = this.alternatives.iterator();
+	SpanOrQuery soquery = new SpanOrQuery( clause.next().toQuery() );
 	while (clause.hasNext()) {
-	    soquery.addClause( clause.next() );
+	    soquery.addClause( clause.next().toQuery() );
 	};
 	return (SpanQuery) soquery;
     };
diff --git a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanClassQueryWrapper.java b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanClassQueryWrapper.java
index 865c61e..c455396 100644
--- a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanClassQueryWrapper.java
+++ b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanClassQueryWrapper.java
@@ -4,6 +4,7 @@
 
 import de.ids_mannheim.korap.query.SpanClassQuery;
 import de.ids_mannheim.korap.query.wrap.SpanQueryWrapper;
+import de.ids_mannheim.korap.util.QueryException;
 
 import java.util.*;
 
@@ -32,7 +33,7 @@
 	this.number = (byte) 0;
     };
 
-    public SpanQuery toQuery () {
+    public SpanQuery toQuery () throws QueryException {
 	if (this.subquery.isNull())
 	    return (SpanQuery) null;
 
diff --git a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanElementQueryWrapper.java b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanElementQueryWrapper.java
index 92a7090..68b844c 100644
--- a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanElementQueryWrapper.java
+++ b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanElementQueryWrapper.java
@@ -4,6 +4,7 @@
 
 import de.ids_mannheim.korap.query.SpanElementQuery;
 import de.ids_mannheim.korap.query.wrap.SpanQueryWrapper;
+import de.ids_mannheim.korap.util.QueryException;
 
 public class SpanElementQueryWrapper extends SpanQueryWrapper {
     String element;
@@ -14,7 +15,7 @@
 	this.element = element;
     };
 
-    public SpanQuery toQuery () {
+    public SpanQuery toQuery () throws QueryException {
 	return (SpanQuery) new SpanElementQuery(this.field, this.element);
     };
 
diff --git a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanEmptyTokenWrapper.java b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanEmptyTokenWrapper.java
deleted file mode 100644
index a4691f0..0000000
--- a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanEmptyTokenWrapper.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package de.ids_mannheim.korap.query.wrap;
-
-import org.apache.lucene.search.spans.SpanQuery;
-import de.ids_mannheim.korap.query.wrap.SpanQueryWrapper;
-
-import java.util.*;
-
-/**
- * Implement an empty token
- */
-public class SpanEmptyTokenWrapper extends SpanQueryWrapper {
-};
diff --git a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanMatchModifyQueryWrapper.java b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanMatchModifyQueryWrapper.java
index 8e9a812..7faadf8 100644
--- a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanMatchModifyQueryWrapper.java
+++ b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanMatchModifyQueryWrapper.java
@@ -2,6 +2,8 @@
 
 import org.apache.lucene.search.spans.SpanQuery;
 
+import de.ids_mannheim.korap.util.QueryException;
+
 import de.ids_mannheim.korap.query.SpanMatchModifyClassQuery;
 import de.ids_mannheim.korap.query.wrap.SpanQueryWrapper;
 
@@ -32,7 +34,7 @@
 	this.number = (byte) 0;
     };
 
-    public SpanQuery toQuery () {
+    public SpanQuery toQuery () throws QueryException {
 	if (this.subquery.isNull())
 	    return (SpanQuery) null;
 	return new SpanMatchModifyClassQuery(this.subquery.toQuery(), this.number);
diff --git a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanQuantifierQueryWrapper.java b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanQuantifierQueryWrapper.java
deleted file mode 100644
index 1926310..0000000
--- a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanQuantifierQueryWrapper.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package de.ids_mannheim.korap.query.wrap;
-
-import java.util.*;
-
-import org.apache.lucene.index.Term;
-import org.apache.lucene.search.Query;
-
-import de.ids_mannheim.korap.query.wrap.SpanQueryWrapper;
-import org.apache.lucene.search.spans.SpanQuery;
-
-// This might be irrelevant now with repetition!
-
-public class SpanQuantifierQueryWrapper extends SpanQueryWrapper {
-    private String field;
-
-    public SpanQuantifierQueryWrapper (String field) {
-	this.field = field;
-    };
-
-    public SpanQuery toQuery () {
-	return (SpanQuery) null;
-    };
-
-    public boolean isNull () {
-	return false;
-    };
-
-    /*
-
-Only support spans with minimal one occurrence and then
-flag spans with NOT_NECESSARY.
-This unfortunately means to support this in at least spanNextQuery
-Problem: Queries without context:
-
-[]*[s:tree]? -> matches everything!
-
-The any segment is special, it shuld be supported by a special
-spanNextQuery, where it adds a position (or more) to the matching span.
-spanNext(Query1, ANY)
-
-      API idea:
-      opt();
-      star();
-      plus();
-      occ(2);
-      occ(2, this.UNLIMITED);
-      occ(0, 4);
-      occ(5, 8);
-
-      Implementation idea:
-      This query should work similar to NextSpans with looking at all matching spans
-      in order per document, returning matching positions for all sequences in the boundary.
-      All actions should be translated to {x,y} boundaries.
-      ?     -> {0,1}
-      +     -> {1,UNL}
-      *     -> {0,UNL}
-      (2)   -> {2,2}
-      (,3)  -> {0,3}
-      (3,)  -> {3,UNL}
-      (3,4) -> {3,4}
-
-      oldSpanEnd = X;
-      For (i = 0; i < orderedSpans.length; i) {
-      # ...
-      };
-
-    */
-};
-
diff --git a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanQueryWrapper.java b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanQueryWrapper.java
index 30fe7b9..3022adb 100644
--- a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanQueryWrapper.java
+++ b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanQueryWrapper.java
@@ -1,6 +1,7 @@
 package de.ids_mannheim.korap.query.wrap;
 
 import org.apache.lucene.search.spans.SpanQuery;
+import de.ids_mannheim.korap.util.QueryException;
 
 // TODO: Add warning and error
 
@@ -11,14 +12,19 @@
  * @author Nils Diewald
  */
 public class SpanQueryWrapper {
-    protected boolean isNull = true,
-	              isOptional = false,
-	              isNegative = false;
     protected int min = 1,
 	          max = 1;
 
+    protected byte number = (byte) 0;
+    protected boolean hasClass = false;
+
+    protected boolean isNull = true,
+	              isOptional = false,
+ 	              isNegative = false,
+	              isEmpty = false;
+
     // Serialize query to Lucene SpanQuery
-    public SpanQuery toQuery () {
+    public SpanQuery toQuery () throws QueryException {
 	return (SpanQuery) null;
     };
 
@@ -42,15 +48,95 @@
 	return this.isNegative;
     };
 
+    // The subquery should match everything, like in
+    // "the []"
+    public boolean isEmpty () {
+	return this.isEmpty;
+    };
+
+    // Check, if the query may be an anchor
+    // in a SpanSequenceQueryWrapper
+    public boolean maybeAnchor () {
+	if (this.isNegative())
+	    return false;
+
+	if (this.isOptional())
+	    return false;
+
+	if (this.isEmpty())
+	    return false;
+
+	return true;
+    };
+
+    public boolean maybeExtension () {
+	return !this.maybeAnchor();
+    };
+
     // Repetition queries may be more specific regarding repetition
-    // This is a minimum repetition value
-    public int min () {
+    // Get minimum repetition value
+    public int getMin () {
 	return this.min;
     };
 
     // Repetition queries may be more specific regarding repetition
-    // This is a maximum repetition value
-    public int max () {
+    // Get maximum repetition value
+    public int getMax () {
 	return this.max;
     };
+
+    // Set minimum repetition value
+    public SpanQueryWrapper setMin (int min) {
+	this.min = min;
+	return this;
+    };
+
+    // Set maximum repetition value
+    public SpanQueryWrapper setMax (int max) {
+	this.max = max;
+	return this;
+    };
+
+
+    // Empty tokens may have class information
+    public boolean hasClass () {
+	return this.hasClass;
+    };
+
+    public SpanQueryWrapper hasClass (boolean value) {
+	this.hasClass = value;
+	return this;
+    };
+
+    // Get class number
+    public byte getClassNumber () {
+	return this.number;
+    };
+
+    // Set class number
+    public SpanQueryWrapper setClassNumber (byte number) {
+	this.hasClass = true;
+	this.number = number;
+	return this;
+    };
+
+    // Set class number
+    public SpanQueryWrapper setClassNumber (short number) {
+	return this.setClassNumber((byte) number);
+    };
+
+    // Set class number
+    public SpanQueryWrapper setClassNumber (int number) {
+	return this.setClassNumber((byte) number);
+    };
+
+    public String toString () {
+	String string = "" +
+	    (this.isNull() ? "isNull" : "notNull") +
+	    "-" +
+	    (this.isEmpty() ? "isEmpty" : "notEmpty") +
+	    "-" +
+	    (this.isOptional() ? "isOptional" : "notOptional");
+	return string;
+    };
 };
diff --git a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanRepetitionQueryWrapper.java b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanRepetitionQueryWrapper.java
index b46d929..3b9763d 100644
--- a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanRepetitionQueryWrapper.java
+++ b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanRepetitionQueryWrapper.java
@@ -4,14 +4,30 @@
 
 import de.ids_mannheim.korap.query.SpanRepetitionQuery;
 import de.ids_mannheim.korap.query.wrap.SpanQueryWrapper;
+import de.ids_mannheim.korap.util.QueryException;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+// DEAL WITH NEGATIVITY
 
 public class SpanRepetitionQueryWrapper extends SpanQueryWrapper {
     private SpanQueryWrapper subquery;
 
+    // Logger
+    private final static Logger log = LoggerFactory.getLogger(SpanSequenceQueryWrapper.class);
+
+    public SpanRepetitionQueryWrapper () {
+	this.isEmpty = true;
+	this.isNull = false;
+    };
+
     // This is for exact enumbered repetition, like in a{3}
     public SpanRepetitionQueryWrapper (SpanQueryWrapper subquery, int exact) {
-	this.subquery = subquery;
+	if (!subquery.isEmpty())
+	    this.subquery = subquery;
+	else
+	    this.isEmpty = true;
 
 	if (exact < 1 || this.subquery.isNull()) {
 	    this.isNull = true;
@@ -28,7 +44,10 @@
     // This is for a range of repetitions, like in a{2,3}, a{,4}, a{3,}, a+, a*, a?
     public SpanRepetitionQueryWrapper (SpanQueryWrapper subquery, int min, int max) {
 
-	this.subquery = subquery;
+	if (!subquery.isEmpty())
+	    this.subquery = subquery;
+	else
+	    this.isEmpty = true;
 
 	// Subquery may be an empty token
 	if (this.subquery.isNull()) {
@@ -52,12 +71,17 @@
 
 
     // Serialize to Lucene SpanQuery
-    public SpanQuery toQuery () {
+    public SpanQuery toQuery () throws QueryException {
 
 	// The query is null
 	if (this.isNull)
 	    return (SpanQuery) null;
 
+	if (this.isEmpty) {
+	    log.error("You can't queryize an empty query");
+	    return (SpanQuery) null;
+	};
+
 	// The query is not a repetition query at all, but may be optional
 	if (this.min == 1 && this.max == 1)
 	    return this.subquery.toQuery();
@@ -72,6 +96,8 @@
     };
 
     public boolean isNegative () {
+	if (this.subquery == null)
+	    return false;
 	return this.subquery.isNegative();
     };
 };
diff --git a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanSegmentQueryWrapper.java b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanSegmentQueryWrapper.java
index 21032a9..a434abb 100644
--- a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanSegmentQueryWrapper.java
+++ b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanSegmentQueryWrapper.java
@@ -13,9 +13,11 @@
 import de.ids_mannheim.korap.query.wrap.SpanWildcardQueryWrapper;
 import de.ids_mannheim.korap.query.SpanSegmentQuery;
 
+import de.ids_mannheim.korap.util.QueryException;
+
+
 /**
  * @author Nils Diewald
- * @version 0.01
  *
  * Creates a query object for segments, i.e. terms in a term vector
  * sharing the same position. A SpanSegment can include simple string terms,
@@ -23,8 +25,8 @@
  */
 
 public class SpanSegmentQueryWrapper extends SpanQueryWrapper {
-    public ArrayList<SpanQuery> inclusive;
-    public ArrayList<SpanQuery> exclusive;
+    public ArrayList<SpanQueryWrapper> inclusive;
+    public ArrayList<SpanQueryWrapper> exclusive;
     private String field;
 
     /**
@@ -34,8 +36,8 @@
      */
     public SpanSegmentQueryWrapper (String field) {
 	this.field = field;
-	this.inclusive = new ArrayList<SpanQuery>();
-	this.exclusive = new ArrayList<SpanQuery>();
+	this.inclusive = new ArrayList<SpanQueryWrapper>();
+	this.exclusive = new ArrayList<SpanQueryWrapper>();
     };
 
     /**
@@ -47,14 +49,14 @@
     public SpanSegmentQueryWrapper (String field, String ... terms) {
 	this(field);
 	for (int i = 0; i < terms.length; i++) {
-	    this.inclusive.add((SpanQuery) new SpanTermQuery(new Term(field, terms[i])));
+	    this.inclusive.add(new SpanSimpleQueryWrapper(field, terms[i]));
 	    this.isNull = false;
 	};
     };
 
     public SpanSegmentQueryWrapper (String field, SpanRegexQueryWrapper re) {
 	this(field);
-	this.inclusive.add((SpanQuery) re.toQuery());
+	this.inclusive.add(re);
 	this.isNull = false;
     };
 
@@ -63,7 +65,7 @@
 	if (!alter.isNull()) {
 	    if (alter.isNegative())
 		this.isNegative = true;
-	    this.inclusive.add((SpanQuery) alter.toQuery());
+	    this.inclusive.add(alter);
 	    this.isNull = false;
 	};
     };
@@ -72,33 +74,35 @@
 	this(field);
 
 	if (!ssq.isNull()) {
-	    Iterator<SpanQuery> clause = ssq.inclusive.iterator();
+	    Iterator<SpanQueryWrapper> clause = ssq.inclusive.iterator();
 	    while (clause.hasNext()) {
-		this.inclusive.add( (SpanQuery) clause.next().clone() );
+		this.inclusive.add( (SpanQueryWrapper) clause.next() ); 
+		// .clone()
 	    };
 
 	    clause = ssq.exclusive.iterator();
 	    while (clause.hasNext()) {
-		this.exclusive.add( (SpanQuery) clause.next().clone() );
+		this.exclusive.add( (SpanQueryWrapper) clause.next() );  
+		// .clone()
 	    };
 	    this.isNull = false;
 	};
     };
 
     public SpanSegmentQueryWrapper with (String term) {
-	this.inclusive.add(new SpanTermQuery(new Term(field, term)));
+	this.inclusive.add(new SpanSimpleQueryWrapper(field, term));
 	this.isNull = false;
 	return this;
     };
 
-    public SpanSegmentQueryWrapper with (SpanRegexQueryWrapper re) {
-	this.inclusive.add((SpanQuery) re.toQuery());
+    public SpanSegmentQueryWrapper with (SpanQueryWrapper re) {
+	this.inclusive.add((SpanQueryWrapper) re);
 	this.isNull = false;
 	return this;
     };
 
     public SpanSegmentQueryWrapper with (SpanWildcardQueryWrapper wc) {
-	this.inclusive.add((SpanQuery) wc.toQuery());
+	this.inclusive.add((SpanQueryWrapper) wc);
 	this.isNull = false;
 	return this;
     };
@@ -107,7 +111,7 @@
 	if (!alter.isNull()) {
 	    if (alter.isNegative())
 		this.isNegative = true;
-	    this.inclusive.add((SpanQuery) alter.toQuery());
+	    this.inclusive.add(alter);
 	    this.isNull = false;
 	};
 	return this;
@@ -116,10 +120,10 @@
     // Identical to without
     public SpanSegmentQueryWrapper with (SpanSegmentQueryWrapper seg) {
 	if (!seg.isNull()) {
-	    for (SpanQuery sq : seg.inclusive) {
+	    for (SpanQueryWrapper sq : seg.inclusive) {
 		this.inclusive.add(sq);
 	    };
-	    for (SpanQuery sq : seg.exclusive) {
+	    for (SpanQueryWrapper sq : seg.exclusive) {
 		this.exclusive.add(sq);
 	    };
 	    this.isNull = false;
@@ -128,19 +132,21 @@
     };
 
     public SpanSegmentQueryWrapper without (String term) {
-	this.exclusive.add(new SpanTermQuery(new Term(field, term)));
+	this.exclusive.add(new SpanSimpleQueryWrapper(field, term));
 	this.isNull = false;
 	return this;
     };
 
+    // TODO: THESE MAYBE NOT NECESSARY:
+
     public SpanSegmentQueryWrapper without (SpanRegexQueryWrapper re) {
-	this.exclusive.add((SpanQuery) re.toQuery());
+	this.exclusive.add(re);
 	this.isNull = false;
 	return this;
     };
 
     public SpanSegmentQueryWrapper without (SpanWildcardQueryWrapper wc) {
-	this.exclusive.add((SpanQuery) wc.toQuery());
+	this.exclusive.add(wc);
 	this.isNull = false;
 	return this;
     };
@@ -148,10 +154,10 @@
     public SpanSegmentQueryWrapper without (SpanAlterQueryWrapper alter) {
 	if (!alter.isNull()) {
 	    if (alter.isNegative()) {
-		this.inclusive.add((SpanQuery) alter.toQuery());
+		this.inclusive.add(alter);
 	    }
 	    else {
-		this.exclusive.add((SpanQuery) alter.toQuery());
+		this.exclusive.add(alter);
 	    };
 	    this.isNull = false;
 	};
@@ -166,7 +172,7 @@
 	return this;
     };
 
-    public SpanQuery toQuery () {
+    public SpanQuery toQuery () throws QueryException {
 	if (this.isNull || (this.inclusive.size() + this.exclusive.size() == 0)) {
 	    return (SpanQuery) null;
 	}
@@ -188,25 +194,25 @@
 	return (SpanQuery) null;
     };
 
-    private SpanQuery _listToQuery (ArrayList<SpanQuery> list) {
-	SpanQuery query = list.get(0);
+    private SpanQuery _listToQuery (ArrayList<SpanQueryWrapper> list) throws QueryException {
+	SpanQuery query = list.get(0).toQuery();
 
 	for (int i = 1; i < list.size(); i++) {
-	    query = new SpanSegmentQuery(query, list.get(i));
+	    query = new SpanSegmentQuery(query, list.get(i).toQuery());
 	};
 
 	return (SpanQuery) query;
     };
 
-    private SpanQuery _listToOrQuery (ArrayList<SpanQuery> list) {
+    private SpanQuery _listToOrQuery (ArrayList<SpanQueryWrapper> list) throws QueryException {
 	if (list.size() == 1) {
-	    return (SpanQuery) list.get(0);
+	    return (SpanQuery) list.get(0).toQuery();
 	};
 
-	Iterator<SpanQuery> clause = list.iterator();
-	SpanOrQuery soquery = new SpanOrQuery( clause.next() );
+	Iterator<SpanQueryWrapper> clause = list.iterator();
+	SpanOrQuery soquery = new SpanOrQuery( clause.next().toQuery() );
 	while (clause.hasNext()) {
-	    soquery.addClause( clause.next() );
+	    soquery.addClause( clause.next().toQuery() );
 	};
 	return (SpanQuery) soquery;
     };
diff --git a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanSequenceQueryWrapper.java b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanSequenceQueryWrapper.java
index 2afb15b..297281e 100644
--- a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanSequenceQueryWrapper.java
+++ b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanSequenceQueryWrapper.java
@@ -9,11 +9,14 @@
 import de.ids_mannheim.korap.query.SpanMultipleDistanceQuery;
 
 import de.ids_mannheim.korap.query.wrap.SpanQueryWrapper;
+import de.ids_mannheim.korap.query.wrap.SpanSimpleQueryWrapper;
 import de.ids_mannheim.korap.query.wrap.SpanSegmentQueryWrapper;
 import de.ids_mannheim.korap.query.wrap.SpanAlterQueryWrapper;
 import de.ids_mannheim.korap.query.wrap.SpanRegexQueryWrapper;
 import de.ids_mannheim.korap.query.wrap.SpanWildcardQueryWrapper;
 
+import de.ids_mannheim.korap.util.QueryException;
+
 import org.apache.lucene.index.Term;
 import org.apache.lucene.search.spans.SpanQuery;
 import org.apache.lucene.search.spans.SpanTermQuery;
@@ -22,7 +25,9 @@
 import org.slf4j.LoggerFactory;
 
 /*
-TODO: Make isNegative work!
+  TODO:
+  Make isNegative work!
+  Make isEmpty work!
 */
 
 
@@ -30,311 +35,162 @@
  * Deserialize complexe sequence queries to Lucene SpanQueries.
  *
  * @author Nils Diewald
+ * @version 0.02
  */
 public class SpanSequenceQueryWrapper extends SpanQueryWrapper {
     private String field;
-    private ArrayList<SpanQuery> segments;
+    private ArrayList<SpanQueryWrapper> segments;
     private ArrayList<DistanceConstraint> constraints;
 
     // Logger
     private final static Logger log = LoggerFactory.getLogger(SpanSequenceQueryWrapper.class);
 
     // This advices the java compiler to ignore all loggings
-    public static final boolean DEBUG = true;
-    
-    private boolean
-	isInOrder = true,
-	isOptional = true,
-	lastIsOptional = false,
-	firstIsOptional = false;
+    public static final boolean DEBUG = false;
 
+    private boolean isInOrder = true;
+
+    /**
+     * Empty constructor.
+     */
     public SpanSequenceQueryWrapper (String field) {
 	this.field = field;
-	this.segments = new ArrayList<SpanQuery>(2);
+	this.segments = new ArrayList<SpanQueryWrapper>(2);
     };
 
+
+    /**
+     * Constructor accepting term sequences.
+     */
     public SpanSequenceQueryWrapper (String field, String ... terms) {
 	this(field);
 	for (int i = 0; i < terms.length; i++) {
-	    this.segments.add((SpanQuery) new SpanTermQuery(new Term(field, terms[i])));
-	    this.isOptional = false;
+	    this.segments.add(
+                new SpanSimpleQueryWrapper(
+                    new SpanTermQuery(new Term(field, terms[i]))
+                )
+            );
 	};
 	this.isNull = false;
     };
 
+
+    /**
+     * Constructor accepting SpanQuery sequences.
+     */
     public SpanSequenceQueryWrapper (String field, SpanQuery sq) {
 	this(field);
-	if (DEBUG)
-	    log.trace("New spanquery sequence " + sq.toString());
-	this.segments.add((SpanQuery) sq);
-	this.isOptional = false;
+	this.segments.add(new SpanSimpleQueryWrapper(sq));
 	this.isNull = false;
     };
 
+
+    /**
+     * Constructor accepting SpanQueryWrapper sequences.
+     * These wrappers may be optional, negative or empty.
+     */
     public SpanSequenceQueryWrapper (String field, SpanQueryWrapper sswq) {
 	this(field);
 
-	if (!sswq.isNull()) {
+	// Ignore null queries
+	if (sswq.isNull())
+	    return;
 
-	    if (sswq.isNegative())
-		this.isNegative = true;
-	    
-	    this.segments.add((SpanQuery) sswq.toQuery());
-	    this.isNull = false;
-	    if (sswq.isOptional()) {
-		if (DEBUG)
-		    log.trace("New optional query sequence " +
-			      sswq.toQuery().toString());
-		this.isOptional = true;
-		this.lastIsOptional = true;
-		this.firstIsOptional = true;
+	if (DEBUG && !sswq.isEmpty) {
+	    try {
+		log.trace("New span sequence {}", sswq.toQuery().toString());
 	    }
-	    else {
-		this.isOptional = false;
-		if (DEBUG)
-		    log.trace("New non-optional query sequence " +
-			      sswq.toQuery().toString());
+	    catch (QueryException qe) {
+		log.trace("Unable to serialize query {}", qe.getMessage());
 	    };
 	};
+
+	this.segments.add(sswq);
+	this.isNull = false;
     };
 
-    public SpanSequenceQueryWrapper (String field, SpanRegexQueryWrapper re) {
-	this(field);
-	if (!re.isNull()) {
-	    this.segments.add((SpanQuery) re.toQuery());
-	    this.isNull = false;
-	    this.isOptional = false;
-	};
-    };
 
-    public SpanSequenceQueryWrapper (String field, SpanWildcardQueryWrapper wc) {
-	this(field);
-	if (!wc.isNull()) {
-	    this.segments.add((SpanQuery) wc.toQuery());
-	    this.isOptional = false;
-	    this.isNull = false;
-	};
-    };
-
-    public SpanQuery get (int index) {
-	return this.segments.get(index);
-    };
-
-    public void set (int index, SpanQuery sq) {
-	this.segments.set(index, sq);
-    };
-
+    /**
+     * Append a term to the sequence.
+     */
     public SpanSequenceQueryWrapper append (String term) {
 	return this.append(
-	    (SpanQuery) new SpanTermQuery(new Term(field, term))
+	    new SpanSimpleQueryWrapper(
+                new SpanTermQuery(new Term(field, term))
+	    )
         );
     };
-    
+
+
+    /**
+     * Append a SpanQuery to the sequence.
+     */
     public SpanSequenceQueryWrapper append (SpanQuery query) {
-	this.isNull     = false;
-	this.isOptional = false;
-
-	// Check if there has to be alternation magic in action
-	if (this.lastIsOptional) {
-	    if (DEBUG)
-		log.trace("Append non-opt query to opt query " +
-			  query.toString());
-
-	    SpanAlterQueryWrapper saqw = new SpanAlterQueryWrapper(field, query);
-	    SpanSequenceQueryWrapper ssqw = new SpanSequenceQueryWrapper(field, query);
-
-	    // Remove last element of the list and prepend it
-	    ssqw.prepend(this.segments.remove(this.segments.size() - 1));
-	    saqw.or(ssqw);
-
-	    // Update boundary optionality
-	    if (this.firstIsOptional && this.segments.size() == 0)
-		this.firstIsOptional = false;
-	    
-	    this.lastIsOptional = false;
-
-	    this.segments.add((SpanQuery) saqw.toQuery());
-	}
-	else {
-	    if (DEBUG)
-		log.trace("Append non-opt query to non-opt query " +
-			  query.toString());
-
-	    this.segments.add(query);
-	};
-	
-	return this;
+	return this.append(new SpanSimpleQueryWrapper(query));
     };
 
+
+    /**
+     * Append a SpanQueryWrapper to the sequence.
+     */
     public SpanSequenceQueryWrapper append (SpanQueryWrapper ssq) {
+	if (ssq.isNull())
+	    return this;
 
-	if (DEBUG)
-	    log.trace("Try to append query {}", ssq.toString());
+	this.isNull = false;
+	this.segments.add(ssq);
 
-	if (!ssq.isNull()) {
-
-	    if (DEBUG)
-		log.trace("THe query {} is not null", ssq.toString());
-
-	    if (ssq.isNegative())
-		this.isNegative = true;
-	    
-	    SpanQuery appendQuery = ssq.toQuery();
-	    if (!ssq.isOptional()) {
-		if (DEBUG)
-		    log.trace("Append non-opt query to non-opt query {}",
-			      appendQuery.toString());
-		return this.append(appendQuery);
-	    };
-	    
-	    // Situation is ab? or a?b?
-	    if (this.segments.size() != 0) {
-
-		// Remove last element of the list and prepend it
-		SpanQuery lastQuery = this.segments.remove(this.segments.size() - 1);
-		SpanAlterQueryWrapper saqw = new SpanAlterQueryWrapper(field, lastQuery);
-		SpanSequenceQueryWrapper ssqw = new SpanSequenceQueryWrapper(field, appendQuery);
-		ssqw.prepend(lastQuery);
-
-		// Situation is a?b?
-		if (this.lastIsOptional) {
-		    saqw.or(appendQuery);
-		    // last stays optional
-		    if (DEBUG)
-			log.trace("Append opt query to opt query {}",
-				  appendQuery.toString());
-
-		}
-		else if (DEBUG) {
-		    log.trace("Append opt query to non-opt query {}",
-			      appendQuery.toString());
-		};
-
-		saqw.or(ssqw);
-		this.segments.add((SpanQuery) saqw.toQuery());
-	    }
-	    
-	    // Situation is b?
-	    else {
-		this.segments.add(appendQuery);
-
-		if (DEBUG)
-		    log.trace("Append opt query {}",
-			      appendQuery.toString());
-
-		// Update boundary optionality
-		this.firstIsOptional = true;
-		this.isOptional      = true;
-		this.lastIsOptional  = true;
-	    };
-	    this.isNull = false;
-	};
 	return this;
     };
 
-    public SpanSequenceQueryWrapper append (SpanRegexQueryWrapper srqw) {
-	if (!srqw.isNull()) {
-	    return this.append((SpanQuery) srqw.toQuery());
-	};
-	return this;
-    };
-    
-    public SpanSequenceQueryWrapper append (SpanWildcardQueryWrapper swqw) {
-	if (!swqw.isNull()) {
-	    return this.append((SpanQuery) swqw.toQuery());
-	};
-	return this;
-    };
-
+    /**
+     * Prepend a term to the sequence.
+     */
     public SpanSequenceQueryWrapper prepend (String term) {
-	return this.prepend(new SpanTermQuery(new Term(field, term)));
+	return this.prepend(
+            new SpanSimpleQueryWrapper(
+	        new SpanTermQuery(new Term(field, term))
+	    )
+        );
     };
 
+
+    /**
+     * Prepend a SpanQuery to the sequence.
+     */
     public SpanSequenceQueryWrapper prepend (SpanQuery query) {
-	this.isNull     = false;
-	this.isOptional = false;
-	
-	// Check if there has to be alternation magic in action
-	if (this.firstIsOptional) {
-	    SpanAlterQueryWrapper saqw = new SpanAlterQueryWrapper(field, query);
-	    SpanSequenceQueryWrapper ssqw = new SpanSequenceQueryWrapper(field, query);
-	    // Remove last element of the list and prepend it
-	    ssqw.append(this.segments.remove(0));
-	    saqw.or(ssqw);
-
-	    // Update boundary optionality
-	    if (this.lastIsOptional && this.segments.size() == 0)
-		this.lastIsOptional = false;
-	    this.firstIsOptional = false;
-
-	    this.segments.add(0, (SpanQuery) saqw.toQuery());
-	}
-	else {
-	    this.segments.add(0,query);
-	};
-	return this;
+	return this.prepend(
+            new SpanSimpleQueryWrapper(query)
+        );
     };
 
+    /**
+     * Prepend a SpanQueryWrapper to the sequence.
+     */
     public SpanSequenceQueryWrapper prepend (SpanQueryWrapper ssq) {
-	if (!ssq.isNull()) {
+	if (ssq.isNull())
+	    return this;
 
-	    if (ssq.isNegative())
-		this.isNegative = true;
-	    
-	    SpanQuery prependQuery = ssq.toQuery();
-	    if (!ssq.isOptional()) {
-		return this.prepend(prependQuery);
-	    };
-	    
-	    // Situation is b?a or b?a?
-	    if (this.segments.size() != 0) {
-		// Remove first element of the list and append it
-		SpanQuery firstQuery = this.segments.remove(0);
-		SpanAlterQueryWrapper saqw = new SpanAlterQueryWrapper(field, firstQuery);
-		SpanSequenceQueryWrapper ssqw = new SpanSequenceQueryWrapper(field, prependQuery);
-		ssqw.append(firstQuery);
+	this.isNull = false;
+	this.segments.add(0, ssq);
 
-		// Situation is b?a?
-		if (this.firstIsOptional)
-		    saqw.or(prependQuery);
-		// first stays optional
-
-		saqw.or(ssqw);
-		this.segments.add(0, (SpanQuery) saqw.toQuery());
-	    }
-	    
-	    // Situation is b?
-	    else {
-		this.segments.add(prependQuery);
-
-		// Update boundary optionality
-		this.firstIsOptional = true;
-		this.isOptional      = true;
-		this.lastIsOptional  = true;
-	    };
-	    this.isNull = false;
-	};
 	return this;
     };
 
-    public SpanSequenceQueryWrapper prepend (SpanRegexQueryWrapper re) {
-	if (!re.isNull()) {
-	    return this.prepend(re.toQuery());
-	};
-	return this;
-    };
 
-    public SpanSequenceQueryWrapper prepend (SpanWildcardQueryWrapper swqw) {
-	if (!swqw.isNull()) {
-	    return this.prepend(swqw.toQuery());
-	};
-	return this;
-    };
-
+    /**
+     * Add a sequence constraint to the sequence for tokens,
+     * aka distance constraints.
+     */
     public SpanSequenceQueryWrapper withConstraint (int min, int max) {
 	return this.withConstraint(min, max, false);
     };
 
+
+    /**
+     * Add a sequence constraint to the sequence for tokens,
+     * aka distance constraints (with exclusion).
+     */
     public SpanSequenceQueryWrapper withConstraint (int min, int max, boolean exclusion) {
 	if (this.constraints == null)
 	    this.constraints = new ArrayList<DistanceConstraint>(1);
@@ -342,10 +198,20 @@
 	return this;
     };
 
+
+    /**
+     * Add a sequence constraint to the sequence for various units,
+     * aka distance constraints.
+     */
     public SpanSequenceQueryWrapper withConstraint (int min, int max, String unit) {
 	return this.withConstraint(min, max, unit, false);
     };
+
     
+    /**
+     * Add a sequence constraint to the sequence for various units,
+     * aka distance constraints (with exclusion).
+     */
     public SpanSequenceQueryWrapper withConstraint (int min,
 						    int max,
 						    String unit,
@@ -362,13 +228,63 @@
 	return this;
     };
 
-    
-    public SpanQuery toQuery () {
-	if (this.segments.size() == 0 || this.isNull) {
+    /**
+     * Respect the order of distances.
+     */
+    public void setInOrder (boolean isInOrder) {
+	this.isInOrder = isInOrder;
+    };
+
+    /**
+     * Check if the order is relevant.
+     */
+    public boolean isInOrder () {
+	return this.isInOrder;
+    };
+
+    /**
+     * Check if there are constraints defined for the sequence.
+     */
+    public boolean hasConstraints () {
+	if (this.constraints == null)
+	    return false;
+	if (this.constraints.size() <= 0)
+	    return false;
+	return true;
+    };
+
+
+    /**
+     * Serialize Query to Lucene SpanQueries
+     */
+    public SpanQuery toQuery () throws QueryException {
+
+	int size = this.segments.size();
+
+	// Nothing to do
+	if (size == 0 || this.isNull)
 	    return (SpanQuery) null;
+
+	if (size == 1) {
+	    if (this.segments.get(0).maybeAnchor())
+		return (SpanQuery) this.segments.get(0).toQuery();
+
+	    if (this.segments.get(0).isEmpty())
+		throw new QueryException("Sequence is not allowed to be empty");
+	    if (this.segments.get(0).isOptional())
+		throw new QueryException("Sequence is not allowed to be optional");
+	    if (this.segments.get(0).isNegative())
+		throw new QueryException("Sequence is not allowed to be negative");
 	};
 
-	SpanQuery query = this.segments.get(0);
+	if (!_solveProblematicSequence(size)) {
+	    if (this.segments.get(0).isNegative())
+		throw new QueryException("Sequence contains unresolvable "+
+					 "empty, optional, or negative segments");
+	};
+
+	// Create the initial query
+	SpanQuery query = this.segments.get(0).toQuery();
 
 	// NextQueries:
 	if (this.constraints == null || this.constraints.size() == 0 ||
@@ -378,7 +294,7 @@
 	    for (int i = 1; i < this.segments.size(); i++) {
 		query = new SpanNextQuery(
 	            query,
-		    this.segments.get(i) // Todo: Maybe payloads are not necessary
+		    this.segments.get(i).toQuery()
 		);
 	    };
 	    return (SpanQuery) query;
@@ -393,9 +309,9 @@
 		for (int i = 1; i < this.segments.size(); i++) {
 		    SpanDistanceQuery sdquery = new SpanDistanceQuery(
 			    query,
-				this.segments.get(i),
-				constraint,
-				true
+			    this.segments.get(i).toQuery(),
+			    constraint,
+			    true
 		    );
 		    query = (SpanQuery) sdquery;
 		};
@@ -405,8 +321,8 @@
 	    else {
 		for (int i = 1; i < this.segments.size(); i++) {
 		    SpanDistanceQuery sdquery = new SpanDistanceQuery(
-	                query,
-			this.segments.get(i),
+			query,
+			this.segments.get(i).toQuery(),
 			constraint,
 			true
 		    );
@@ -421,29 +337,206 @@
 	for (int i = 1; i < this.segments.size(); i++) {
 	    query = new SpanMultipleDistanceQuery(
 	        query,
-		this.segments.get(i),
+		this.segments.get(i).toQuery(),
 		this.constraints,
 		isInOrder,
 		true
 	    );
 	};
-
 	return (SpanQuery) query;
     };
 
-    public void setInOrder (boolean isInOrder) {
-	this.isInOrder = isInOrder;
+    /*
+      While there is a segment isNegative() or isOptional() or isEmpty() do
+      - look for an anchor next to it
+      - merge the problematic segment with the anchor
+      - go on
+    */
+    private boolean _solveProblematicSequence (int size) throws QueryException {
+
+	// Check if there is a problematic segment
+	SpanQueryWrapper underScrutiny;
+	boolean noRemainingProblem = true;
+	int i = 0;
+
+	if (DEBUG)
+	    log.trace("Try to solve a query of {} segments", size);
+
+	for (; i < size;) {
+	    underScrutiny = this.segments.get(i);
+
+	    // Check if there is a problem!
+	    if (!underScrutiny.maybeAnchor()) {
+
+		if (DEBUG)
+		    log.trace("segment {} is problematic", i);
+
+		// [problem][anchor]
+		if (i < (size-1) && this.segments.get(i+1).maybeAnchor()) {
+
+		    // Insert the solution
+		    this.segments.set(
+		        i+1,
+		        _merge(this.segments.get(i+1), underScrutiny, false)
+		    );
+
+		    // Remove the problem
+		    this.segments.remove(i);
+		    size--;
+
+		    if (DEBUG)
+			log.trace("Remove segment {} - now size {}", i, size);
+		}
+
+		// [anchor][problem]
+		else if (i >= 1 && this.segments.get(i-1).maybeAnchor()) {
+		    // Insert the solution
+		    this.segments.set(
+		        i-1,
+		        _merge(this.segments.get(i-1), underScrutiny, true)
+		    );
+
+		    // Remove the problem
+		    this.segments.remove(i);
+		    size--;
+
+		    if (DEBUG)
+			log.trace("Remove segment {} - now size {}", i, size);
+		}
+		else {
+		    noRemainingProblem = false;
+		    i++;
+		};
+	    }
+	    else {
+		i++;
+	    };
+	};
+
+	// There is still a remaining problem
+	if (!noRemainingProblem) {
+
+	    // The size has changed - retry!
+	    if (size != this.segments.size())
+		return _solveProblematicSequence(this.segments.size());
+	    else
+		return true;
+	};
+
+	return false;
     };
 
-    public boolean isInOrder () {
-	return this.isInOrder;
-    };
 
-    public boolean hasConstraints () {
-	if (this.constraints == null)
-	    return false;
-	if (this.constraints.size() <= 0)
-	    return false;
-	return true;
+    // Todo: Deal with negative and optional!
+    // [base=der][base!=Baum]?
+    public SpanQueryWrapper _merge (
+        SpanQueryWrapper anchor,
+	SpanQueryWrapper problem,
+	boolean mergeLeft) throws QueryException {
+
+	// Extend to the right - merge to the left
+	int direction = 1;
+	if (!mergeLeft)
+	    direction = -1;
+
+	if (DEBUG)
+	    log.trace("Will merge two spans to {}", mergeLeft ? "left" : "right");
+	    
+	// Make empty extension to anchor
+	if (problem.isEmpty()) {
+	    SpanQuery query;
+
+	    if (DEBUG)
+		log.trace("Problem is empty");
+
+	    if (problem.hasClass) {
+
+		if (DEBUG)
+		    log.trace("Problem has class {}", problem.getClassNumber());
+
+		query = new SpanExpansionQuery(
+		    anchor.toQuery(),
+		    problem.getMin(),
+		    problem.getMax(),
+		    direction,
+		    problem.getClassNumber(),
+		    true
+		);
+	    }
+	    else {
+
+		if (DEBUG)
+		    log.trace("Problem has no class");
+
+		query = new SpanExpansionQuery(
+		    anchor.toQuery(),
+		    problem.getMin(),
+		    problem.getMax(),
+		    direction,
+		    true
+		);
+	    };
+	    return new SpanSimpleQueryWrapper(query);
+	}
+
+	// make negative extension to anchor
+	else if (problem.isNegative()) {
+
+	    if (DEBUG)
+		log.trace("Problem is negative");
+
+	    SpanQuery query;
+	    if (problem.hasClass) {
+
+		if (DEBUG)
+		    log.trace("Problem has class {}", problem.getClassNumber());
+
+		query = new SpanExpansionQuery(
+		    anchor.toQuery(),
+		    problem.toQuery(),
+		    problem.getMin(),
+		    problem.getMax(),
+		    direction,
+		    problem.getClassNumber(),
+		    true
+		);
+	    }
+	    else {
+		if (DEBUG)
+		    log.trace("Problem has no class");
+
+		query = new SpanExpansionQuery(
+		    anchor.toQuery(),
+		    problem.toQuery(),
+		    problem.getMin(),
+		    problem.getMax(),
+		    direction,
+		    true
+		);
+	    };
+	    return new SpanSimpleQueryWrapper(query);
+	};
+
+	if (DEBUG)
+	    log.trace("Problem is optional");
+
+	// [base=der][base=baum]?
+
+	// [base=der]
+	SpanAlterQueryWrapper saqw = new SpanAlterQueryWrapper(this.field, anchor);
+
+	// [base=der]
+	SpanSequenceQueryWrapper ssqw = new SpanSequenceQueryWrapper(this.field, anchor);
+
+	// [base=der][base=baum]
+	if (mergeLeft)
+	    ssqw.append(new SpanSimpleQueryWrapper(problem.toQuery()));
+	// [base=baum][base=der]
+	else
+	    ssqw.prepend(new SpanSimpleQueryWrapper(problem.toQuery()));
+	
+	saqw.or(ssqw);
+
+	return (SpanQueryWrapper) saqw;
     };
 };
diff --git a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanSimpleQueryWrapper.java b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanSimpleQueryWrapper.java
new file mode 100644
index 0000000..84cc259
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanSimpleQueryWrapper.java
@@ -0,0 +1,23 @@
+package de.ids_mannheim.korap.query.wrap;
+
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.spans.SpanQuery;
+import org.apache.lucene.search.spans.SpanTermQuery;
+
+public class SpanSimpleQueryWrapper extends SpanQueryWrapper {
+    private SpanQuery query;
+
+    public SpanSimpleQueryWrapper (String field, String term) {
+	this.isNull = false;
+	this.query = new SpanTermQuery(new Term(field, term));
+    };
+
+    public SpanSimpleQueryWrapper (SpanQuery query) {
+	this.isNull = false;
+	this.query = query;
+    };
+
+    public SpanQuery toQuery () {
+	return this.query;
+    };
+};
diff --git a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanWithinQueryWrapper.java b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanWithinQueryWrapper.java
index 0707882..3dd1482 100644
--- a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanWithinQueryWrapper.java
+++ b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanWithinQueryWrapper.java
@@ -6,12 +6,18 @@
 import de.ids_mannheim.korap.query.wrap.SpanSequenceQueryWrapper;
 import de.ids_mannheim.korap.query.wrap.SpanQueryWrapper;
 
+import de.ids_mannheim.korap.util.QueryException;
+
 import java.util.*;
 
 import org.apache.lucene.search.spans.SpanQuery;
 
 /*
   Todo:
+
+  contains(token,token) und matches(token, token) -> termGroup
+
+
   - Exclusivity has to be supported
   - In case the wrap is negative,
     the query has to be interpreted as being exclusive!
@@ -78,7 +84,7 @@
 	    this.isNull = false;
     };
 
-    public SpanQuery toQuery () {
+    public SpanQuery toQuery () throws QueryException {
 	if (this.isNull)
 	    return (SpanQuery) null;
 	
diff --git a/src/test/java/de/ids_mannheim/korap/filter/TestKorapCollection.java b/src/test/java/de/ids_mannheim/korap/filter/TestKorapCollection.java
index e645809..9caa0ab 100644
--- a/src/test/java/de/ids_mannheim/korap/filter/TestKorapCollection.java
+++ b/src/test/java/de/ids_mannheim/korap/filter/TestKorapCollection.java
@@ -26,7 +26,7 @@
 public class TestKorapCollection {
 
     @Test
-    public void filterExample () throws IOException {
+    public void filterExample () throws Exception {
 	
 	// Construct index
 	KorapIndex ki = new KorapIndex();
@@ -90,7 +90,7 @@
     };
 
     @Test
-    public void filterExampleAtomic () throws IOException {
+    public void filterExampleAtomic () throws Exception {
 	
 	// That's exactly the same test class, but with multiple atomic indices
 
@@ -168,7 +168,7 @@
 
 
     @Test
-    public void filterExample2 () throws IOException {
+    public void filterExample2 () throws Exception {
 	
 	// Construct index
 	KorapIndex ki = new KorapIndex();
diff --git a/src/test/java/de/ids_mannheim/korap/highlight/TestHighlight.java b/src/test/java/de/ids_mannheim/korap/highlight/TestHighlight.java
index 3829c4e..d775bcc 100644
--- a/src/test/java/de/ids_mannheim/korap/highlight/TestHighlight.java
+++ b/src/test/java/de/ids_mannheim/korap/highlight/TestHighlight.java
@@ -12,6 +12,9 @@
 import de.ids_mannheim.korap.KorapMatch;
 import de.ids_mannheim.korap.index.FieldDocument;
 
+import de.ids_mannheim.korap.util.QueryException;
+
+
 import static de.ids_mannheim.korap.Test.*;
 
 import static org.junit.Assert.*;
@@ -24,7 +27,7 @@
 public class TestHighlight { // extends LuceneTestCase {
 
     @Test
-    public void checkHighlights () throws IOException  {
+    public void checkHighlights () throws IOException, QueryException  {
 
 	KorapIndex ki = new KorapIndex();
 	String json = new String(
@@ -93,7 +96,7 @@
     };
 
     @Test
-    public void checkHighlightsManually () throws IOException  {
+    public void checkHighlightsManually () throws IOException, QueryException  {
 
 	KorapIndex ki = new KorapIndex();
 	String json = new String(
@@ -134,7 +137,7 @@
 
 
     @Test
-    public void highlightMissingBug () throws IOException  {
+    public void highlightMissingBug () throws IOException, QueryException  {
 	KorapIndex ki = new KorapIndex();
 	FieldDocument fd = new FieldDocument();
 	fd.addString("ID", "doc-1");
diff --git a/src/test/java/de/ids_mannheim/korap/index/TestElementDistanceIndex.java b/src/test/java/de/ids_mannheim/korap/index/TestElementDistanceIndex.java
index c94a7fc..ce969db 100644
--- a/src/test/java/de/ids_mannheim/korap/index/TestElementDistanceIndex.java
+++ b/src/test/java/de/ids_mannheim/korap/index/TestElementDistanceIndex.java
@@ -194,7 +194,7 @@
 	
 	/** Test query from json */
 	@Test
-	public void testCase5() throws IOException{
+	public void testCase5() throws Exception{
 		//System.out.println("testCase4");
 		ki = new KorapIndex();
 		ki.addDocFile(getClass().getResource("/wiki/00001.json.gz").getFile(),true);       
diff --git a/src/test/java/de/ids_mannheim/korap/index/TestFieldDocument.java b/src/test/java/de/ids_mannheim/korap/index/TestFieldDocument.java
index 0b47add..7bf771b 100644
--- a/src/test/java/de/ids_mannheim/korap/index/TestFieldDocument.java
+++ b/src/test/java/de/ids_mannheim/korap/index/TestFieldDocument.java
@@ -93,7 +93,7 @@
     };
 
     @Test
-    public void indexExample2 () throws IOException {
+    public void indexExample2 () throws Exception {
 
 	String json = new String(
 "{" +
@@ -204,7 +204,7 @@
     };
 
     @Test
-    public void queryJSONBsp18 () throws IOException {
+    public void queryJSONBsp18 () throws Exception {
 
 	// Construct index
 	KorapIndex ki = new KorapIndex();
diff --git a/src/test/java/de/ids_mannheim/korap/index/TestIndex.java b/src/test/java/de/ids_mannheim/korap/index/TestIndex.java
index 7dc69d3..d1dd608 100644
--- a/src/test/java/de/ids_mannheim/korap/index/TestIndex.java
+++ b/src/test/java/de/ids_mannheim/korap/index/TestIndex.java
@@ -162,7 +162,7 @@
     };
 
     @Test
-    public void indexLucene () throws IOException {
+    public void indexLucene () throws Exception {
 
 	// Base analyzer for searching and indexing
 	StandardAnalyzer analyzer = new StandardAnalyzer(Version.LUCENE_43);
diff --git a/src/test/java/de/ids_mannheim/korap/index/TestMatchIndex.java b/src/test/java/de/ids_mannheim/korap/index/TestMatchIndex.java
index 0f3fe12..529b74a 100644
--- a/src/test/java/de/ids_mannheim/korap/index/TestMatchIndex.java
+++ b/src/test/java/de/ids_mannheim/korap/index/TestMatchIndex.java
@@ -269,7 +269,7 @@
 
 
     @Test
-    public void indexExample3 () throws IOException {
+    public void indexExample3 () throws Exception {
 	KorapIndex ki = new KorapIndex();
 
 	// abcabcabac
diff --git a/src/test/java/de/ids_mannheim/korap/index/TestNextIndex.java b/src/test/java/de/ids_mannheim/korap/index/TestNextIndex.java
index 85b6db2..8471b20 100644
--- a/src/test/java/de/ids_mannheim/korap/index/TestNextIndex.java
+++ b/src/test/java/de/ids_mannheim/korap/index/TestNextIndex.java
@@ -327,7 +327,7 @@
 	}
 
 	@Test
-	public void indexExample7Distances () throws IOException{
+	public void indexExample7Distances () throws Exception{
 		KorapIndex ki = new KorapIndex();
 		ki.addDoc(createFieldDoc1());		
 		ki.addDoc(createFieldDoc2());		
@@ -347,7 +347,7 @@
 	};
 
 	@Test
-	public void indexExample8Distances () throws IOException{
+	public void indexExample8Distances () throws Exception{
 		KorapIndex ki = new KorapIndex();
 		ki.addDoc(createFieldDoc1());		
 		ki.addDoc(createFieldDoc2());		
diff --git a/src/test/java/de/ids_mannheim/korap/index/TestRegexWildcardIndex.java b/src/test/java/de/ids_mannheim/korap/index/TestRegexWildcardIndex.java
index ab0729f..1c23494 100644
--- a/src/test/java/de/ids_mannheim/korap/index/TestRegexWildcardIndex.java
+++ b/src/test/java/de/ids_mannheim/korap/index/TestRegexWildcardIndex.java
@@ -27,7 +27,7 @@
 public class TestRegexWildcardIndex {
 
     @Test
-    public void indexRegex () throws IOException {
+    public void indexRegex () throws Exception {
 	KorapIndex ki = new KorapIndex();
 
 	// abcabcabac
@@ -84,7 +84,7 @@
     };
 
     @Test
-    public void indexWildcard () throws IOException {
+    public void indexWildcard () throws Exception {
 	KorapIndex ki = new KorapIndex();
 
 	// abcabcabac
@@ -143,7 +143,7 @@
     };
 
     @Test
-    public void indexRegexCaseInsensitive () throws IOException {
+    public void indexRegexCaseInsensitive () throws Exception {
 	KorapIndex ki = new KorapIndex();
 
 	// abcabcabac
@@ -208,7 +208,7 @@
     };
 
     @Test
-    public void indexRegexCombined () throws IOException {
+    public void indexRegexCombined () throws Exception {
 	KorapIndex ki = new KorapIndex();
 
 	// abcabcabac
@@ -244,7 +244,7 @@
 
 
     @Test
-    public void indexRegexWithinRewrite () throws IOException {
+    public void indexRegexWithinRewrite () throws Exception {
 	KorapIndex ki = new KorapIndex();
 
 	// abcabcabac
diff --git a/src/test/java/de/ids_mannheim/korap/index/TestSegmentNegationIndex.java b/src/test/java/de/ids_mannheim/korap/index/TestSegmentNegationIndex.java
index b2f1cd8..7a3851b 100644
--- a/src/test/java/de/ids_mannheim/korap/index/TestSegmentNegationIndex.java
+++ b/src/test/java/de/ids_mannheim/korap/index/TestSegmentNegationIndex.java
@@ -30,7 +30,7 @@
     private Logger log;	
 	
     @Test
-    public void testcaseNegation() throws IOException{
+    public void testcaseNegation() throws Exception {
 	ki = new KorapIndex();
 	ki.addDoc(createFieldDoc0());
 	ki.addDoc(createFieldDoc1());
diff --git a/src/test/java/de/ids_mannheim/korap/query/TestKorapQuery.java b/src/test/java/de/ids_mannheim/korap/query/TestKorapQuery.java
index f6187ad..2eaa1cd 100644
--- a/src/test/java/de/ids_mannheim/korap/query/TestKorapQuery.java
+++ b/src/test/java/de/ids_mannheim/korap/query/TestKorapQuery.java
@@ -4,6 +4,7 @@
 import org.apache.lucene.search.spans.SpanQuery;
 import de.ids_mannheim.korap.KorapQuery;
 
+import de.ids_mannheim.korap.util.QueryException;
 
 import static org.junit.Assert.*;
 import org.junit.Test;
@@ -15,7 +16,7 @@
 public class TestKorapQuery {
 
     @Test
-    public void korapQuerySegment () {
+    public void korapQuerySegment () throws QueryException {
 	SpanQuery sq = new KorapQuery("field1").seg("a").with("b").toQuery();
 	assertEquals("spanSegment(field1:a, field1:b)", sq.toString());
 
@@ -24,7 +25,7 @@
     };
 
     @Test
-    public void korapQueryRegexSegment () {
+    public void korapQueryRegexSegment () throws QueryException {
 	KorapQuery kq = new KorapQuery("field1");
 	SpanQuery sq = kq.seg("a").with(kq.re("b.*c")).toQuery();
 	assertEquals("spanSegment(field1:a, SpanMultiTermQueryWrapper(field1:/b.*c/))", sq.toString());
@@ -35,7 +36,7 @@
     };
 
     @Test
-    public void korapQueryRegexSegment2 () {
+    public void korapQueryRegexSegment2 () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.seg("a").with(kq.or("b").or("c")).toQuery();
 	assertEquals("spanSegment(field:a, spanOr([field:b, field:c]))", sq.toString());
@@ -52,49 +53,49 @@
     };
 
     @Test
-    public void korapQuerySequenceSegment () {
+    public void korapQuerySequenceSegment () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.seq(kq.seg("a").with(kq.or("b", "c"))).append("d").append(kq.re("e.?f")).toQuery();
 	assertEquals("spanNext(spanNext(spanSegment(field:a, spanOr([field:b, field:c])), field:d), SpanMultiTermQueryWrapper(field:/e.?f/))", sq.toString());
     };
 
     @Test
-    public void KorapTagQuery () {
+    public void KorapTagQuery () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.tag("np").toQuery();
 	assertEquals("<field:np />", sq.toString());
     };
 
     @Test
-    public void KorapTagQuery2 () {
+    public void KorapTagQuery2 () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.or(kq.tag("np"), kq.tag("vp")).toQuery();
 	assertEquals("spanOr([<field:np />, <field:vp />])", sq.toString());
     };
 
     @Test
-    public void KorapTagQuery3 () {
+    public void KorapTagQuery3 () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.seq(kq.tag("np"), kq.tag("vp")).toQuery();
 	assertEquals("spanNext(<field:np />, <field:vp />)", sq.toString());
     };
 
     @Test
-    public void KorapTagQuery4 () {
+    public void KorapTagQuery4 () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.seq(kq.tag("np"), kq.tag("vp")).append("test").toQuery();
 	assertEquals("spanNext(spanNext(<field:np />, <field:vp />), field:test)", sq.toString());
     };
 
     @Test
-    public void KorapTagQuery5 () {
+    public void KorapTagQuery5 () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.contains(kq.tag("s"), kq.tag("np")).toQuery();
 	assertEquals("spanContain(<field:s />, <field:np />)", sq.toString());
     };
 
     @Test
-    public void KorapTagQuery6 () {
+    public void KorapTagQuery6 () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.seq(kq.seg("tree"), kq.contains(kq.tag("s"), kq.tag("np")), kq.re("hey.*")).toQuery();
 	assertEquals("spanNext(spanNext(field:tree, spanContain(<field:s />, <field:np />)), SpanMultiTermQueryWrapper(field:/hey.*/))", sq.toString());
@@ -102,135 +103,133 @@
 
 
     @Test
-    public void KorapClassQuery () {
+    public void KorapClassQuery () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.seq(kq.seg("tree"), kq._(1, kq.contains(kq.tag("s"), kq.tag("np"))), kq.re("hey.*")).toQuery();
 	assertEquals("spanNext(spanNext(field:tree, {1: spanContain(<field:s />, <field:np />)}), SpanMultiTermQueryWrapper(field:/hey.*/))", sq.toString());
     };
 
     @Test
-    public void KorapClassQuery2 () {
+    public void KorapClassQuery2 () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq._(kq.seg("base:test")).toQuery();
 	assertEquals("{0: field:base:test}", sq.toString());
     };
 
     @Test
-    public void KorapClassQuery3 () {
+    public void KorapClassQuery3 () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.seq(kq.seg("tree"), kq.contains(kq.tag("s"), kq._(kq.tag("np"))), kq.re("hey.*")).toQuery();
 	assertEquals("spanNext(spanNext(field:tree, spanContain(<field:s />, {0: <field:np />})), SpanMultiTermQueryWrapper(field:/hey.*/))", sq.toString());
     };
 
     @Test
-    public void KorapShrinkQuery () {
+    public void KorapShrinkQuery () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.shrink(kq.tag("np")).toQuery();
 	assertEquals("shrink(0: <field:np />)", sq.toString());
     };
 
     @Test
-    public void KorapShrinkQuery1 () {
+    public void KorapShrinkQuery1 () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.shrink(1, kq.tag("np")).toQuery();
 	assertEquals("shrink(1: <field:np />)", sq.toString());
     };
 
     @Test
-    public void KorapShrinkQuery2 () {
+    public void KorapShrinkQuery2 () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.shrink(1, kq._(1, kq.tag("np"))).toQuery();
 	assertEquals("shrink(1: {1: <field:np />})", sq.toString());
     };
 
     @Test
-    public void KorapShrinkQuery3 () {
+    public void KorapShrinkQuery3 () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.shrink(1, kq._(1, kq.seq(kq.tag("np"), kq._(kq.seg("test").without("no"))))).toQuery();
 	assertEquals("shrink(1: {1: spanNext(<field:np />, {0: spanNot(field:test, field:no, 0, 0)})})", sq.toString());
     };
 
     @Test
-    public void KorapShrinkQuery4 () {
+    public void KorapShrinkQuery4 () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.seq(kq.seg("try1"), kq.shrink(1, kq._(1, kq.seg("try2"))), kq.seg("try3")).toQuery();
 	assertEquals("spanNext(spanNext(field:try1, shrink(1: {1: field:try2})), field:try3)", sq.toString());
     };
 
-
     @Test
-    public void KorapSequenceQuery1 () {
+    public void KorapSequenceQuery1 () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.seq(kq.seg("try1")).append(kq.seg("try2")).toQuery();
 	assertEquals("spanNext(field:try1, field:try2)", sq.toString());
     };
 
     @Test
-    public void KorapSequenceQuery2 () {
+    public void KorapSequenceQuery2 () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.seq(kq.seg("try1")).append(kq.seg("try2")).withConstraint(2,3).toQuery();
 	assertEquals("spanDistance(field:try1, field:try2, [(w[2:3], ordered, notExcluded)])", sq.toString());
     };
 
     @Test
-    public void KorapSequenceQuery3 () {
+    public void KorapSequenceQuery3 () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.seq(kq.seg("try1")).append(kq.seg("try2")).withConstraint(2,3, "s").toQuery();
 	assertEquals("spanElementDistance(field:try1, field:try2, [(s[2:3], ordered, notExcluded)])", sq.toString());
     };
 
     @Test
-    public void KorapSequenceQuery4 () {
+    public void KorapSequenceQuery4 () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.seq(kq.seg("try1")).append(kq.seg("try2")).withConstraint(2,3,"s").withConstraint(5,6,"w").toQuery();
 	assertEquals("spanMultipleDistance(field:try1, field:try2, [(s[2:3], ordered, notExcluded), (w[5:6], ordered, notExcluded)])", sq.toString());
     };
 
     @Test
-    public void KorapSequenceQuery5 () {
+    public void KorapSequenceQuery5 () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.seq(kq.seg("try1")).append(kq.seg("try2")).withConstraint(2,3,true).toQuery();
 	assertEquals("spanDistance(field:try1, field:try2, [(w[2:3], ordered, excluded)])", sq.toString());
     };
 
     @Test
-    public void KorapSequenceQuery6 () {
+    public void KorapSequenceQuery6 () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.seq(kq.seg("try1")).append(kq.seg("try2")).withConstraint(2,3,"s", true).toQuery();
 	assertEquals("spanElementDistance(field:try1, field:try2, [(s[2:3], ordered, excluded)])", sq.toString());
     };
 
     @Test
-    public void KorapSequenceQuery7 () {
+    public void KorapSequenceQuery7 () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.seq(kq.seg("try1")).append(kq.seg("try2")).withConstraint(5,6).withConstraint(2,3,"s",true).toQuery();
 	assertEquals("spanMultipleDistance(field:try1, field:try2, [(w[5:6], ordered, notExcluded), (s[2:3], ordered, excluded)]])", sq.toString());
     };
 
     @Test
-    public void KorapSequenceQuery8 () {
+    public void KorapSequenceQuery8 () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.seq(kq.seg("try1")).append(kq.seg("try2")).append("try3").withConstraint(5,6).withConstraint(2,3,"s",true).toQuery();
 	assertEquals("spanMultipleDistance(spanMultipleDistance(field:try1, field:try2, [(w[5:6], ordered, notExcluded), (s[2:3], ordered, excluded)]]), field:try3, [(w[5:6], ordered, notExcluded), (s[2:3], ordered, excluded)]])", sq.toString());
     };
 
-
     @Test
-    public void KorapWithinQuery1 () {
+    public void KorapWithinQuery1 () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.contains(kq.seg("test"), kq.seg("test2")).toQuery();
 	assertEquals("spanContain(field:test, field:test2)", sq.toString());
     };
 
     @Test
-    public void KorapWithinQuery2 () {
+    public void KorapWithinQuery2 () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.overlaps(kq.seg("test"), kq.seg("test2")).toQuery();
 	assertEquals("spanOverlap(field:test, field:test2)", sq.toString());
     };
 
     @Test
-    public void KorapWithinQuery3 () {
+    public void KorapWithinQuery3 () throws QueryException {
 	KorapQuery kq = new KorapQuery("field");
 	SpanQuery sq = kq.startswith(kq.seg("test"), kq.seg("test2")).toQuery();
 	assertEquals("spanStartsWith(field:test, field:test2)", sq.toString());
diff --git a/src/test/java/de/ids_mannheim/korap/query/TestKorapQueryJSON.java b/src/test/java/de/ids_mannheim/korap/query/TestKorapQueryJSON.java
index 486d0c3..be852ce 100644
--- a/src/test/java/de/ids_mannheim/korap/query/TestKorapQueryJSON.java
+++ b/src/test/java/de/ids_mannheim/korap/query/TestKorapQueryJSON.java
@@ -21,7 +21,7 @@
     private String defaultFoundry = "mate/";
 
     @Test
-    public void queryJSONBsp1 () {
+    public void queryJSONBsp1 () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/bsp1.jsonld").getFile());
 
 	// There is a repetition in here
@@ -32,7 +32,7 @@
     };
 
     @Test
-    public void queryJSONBsp1b () {
+    public void queryJSONBsp1b () throws QueryException {
 
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/bsp1b.jsonld").getFile());
 
@@ -42,7 +42,7 @@
 
 
     @Test
-    public void queryJSONBsp2 () {
+    public void queryJSONBsp2 () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/bsp2.jsonld").getFile());
 
 	// ([base=foo]|[base=bar])[base=foobar]
@@ -50,7 +50,7 @@
     };
 
     @Test
-    public void queryJSONBsp3 () {
+    public void queryJSONBsp3 () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/bsp3.jsonld").getFile());
 
 	// shrink({[base=Mann]})
@@ -58,7 +58,7 @@
     };
 
     @Test
-    public void queryJSONBsp4 () {
+    public void queryJSONBsp4 () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/bsp4.jsonld").getFile());
 
 	// shrink({[base=foo]}[orth=bar])
@@ -66,7 +66,7 @@
     };
 
     @Test
-    public void queryJSONBsp5 () {
+    public void queryJSONBsp5 () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/bsp5.jsonld").getFile());
 
 	// shrink(1:[base=Der]{1:[base=Mann]}) 
@@ -74,7 +74,7 @@
     };
 
     @Test
-    public void queryJSONBsp6 () {
+    public void queryJSONBsp6 () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/bsp6.jsonld").getFile());
 
 	// [base=katze]
@@ -82,7 +82,7 @@
     };
 
     @Test
-    public void queryJSONBsp7 () {
+    public void queryJSONBsp7 () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/bsp7.jsonld").getFile());
 
 	// [!base=Katze]
@@ -91,7 +91,7 @@
     };
 
     @Test
-    public void queryJSONBsp9 () {
+    public void queryJSONBsp9 () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/bsp9.jsonld").getFile());
 
 	// [base=Katze&orth=Katzen]
@@ -99,7 +99,7 @@
     };
 
     @Test
-    public void queryJSONBsp9b () {
+    public void queryJSONBsp9b () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/bsp9b.jsonld").getFile());
 
 	// [base=Katze&orth=Katzen]
@@ -108,7 +108,7 @@
 
 
     @Test
-    public void queryJSONBsp10 () {
+    public void queryJSONBsp10 () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/bsp10.jsonld").getFile());
 
 	// [base=Katze][orth=und][orth=Hunde]
@@ -116,7 +116,7 @@
     };
 
     @Test
-    public void queryJSONBsp11 () {
+    public void queryJSONBsp11 () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/bsp11.jsonld").getFile());
 
 	// [base!=Katze | orth!=Katzen]
@@ -130,7 +130,7 @@
     };
 
     @Test
-    public void queryJSONBsp12 () {
+    public void queryJSONBsp12 () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/bsp12.jsonld").getFile());
 
 	// contains(<np>,[base=Mann])
@@ -138,14 +138,14 @@
     };
 
     @Test
-    public void queryJSONBsp13 () {
+    public void queryJSONBsp13 () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/bsp13.jsonld").getFile());
 
 	assertEquals(sqwi.toQuery().toString(), "spanStartsWith(<tokens:np />, tokens:mate/p:Det)");
     };
 
     @Test
-    public void queryJSONBsp13b () {
+    public void queryJSONBsp13b () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/bsp13b.jsonld").getFile());
 
 	// startswith(<np>,[pos=Det])
@@ -153,7 +153,7 @@
     };
 
     @Test
-    public void queryJSONBsp14 () {
+    public void queryJSONBsp14 () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/bsp14.jsonld").getFile());
 
 	// 'vers{2,3}uch'
@@ -161,7 +161,7 @@
     };
 
     @Test
-    public void queryJSONBsp15 () {
+    public void queryJSONBsp15 () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/bsp15.jsonld").getFile());
 
 	// [orth='vers.*ch']
@@ -169,7 +169,7 @@
     };
 
     @Test
-    public void queryJSONBsp16 () {
+    public void queryJSONBsp16 () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/bsp16.jsonld").getFile());
 
 	// [(base=bar|base=foo)&orth=foobar]
@@ -177,7 +177,7 @@
     };
 
     @Test
-    public void queryJSONBsp17 () {
+    public void queryJSONBsp17 () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/bsp17.jsonld").getFile());
 
 	// within(<np>,[base=Mann])
@@ -192,7 +192,7 @@
     };
 
     @Test
-    public void queryJSONBspClass () {
+    public void queryJSONBspClass () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/bsp-class.jsonld").getFile());
 
 	// within(<np>,[base=Mann])
@@ -201,7 +201,7 @@
 
 
     @Test
-    public void queryJSONcosmas3 () {
+    public void queryJSONcosmas3 () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/cosmas3.json").getFile());
 
 	// "das /+w1:3 Buch"
@@ -209,7 +209,7 @@
     };
 
     @Test
-    public void queryJSONcosmas4 () {
+    public void queryJSONcosmas4 () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/cosmas4.json").getFile());
 
 	// "das /+w1:3,s1:1 Buch"
@@ -217,7 +217,7 @@
     };
 
     @Test
-    public void queryJSONcosmas4b () {
+    public void queryJSONcosmas4b () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/cosmas4b.json").getFile());
 
 	// "das /+w1:3,s1 Buch"
@@ -225,7 +225,7 @@
     };
 
     @Test
-    public void queryJSONcosmas10 () {
+    public void queryJSONcosmas10 () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/cosmas10.json").getFile());
 
 	// "Institut für $deutsche Sprache"
@@ -233,7 +233,7 @@
     };
 
     @Test
-    public void queryJSONcosmas10b () {
+    public void queryJSONcosmas10b () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/cosmas10b.json").getFile());
 
 	// "Institut $FÜR $deutsche Sprache"
@@ -241,7 +241,7 @@
     };
 
     @Test
-    public void queryJSONcosmas16 () {
+    public void queryJSONcosmas16 () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/cosmas16.json").getFile());
 
 	// "$wegen #IN(L) <s>"
@@ -249,7 +249,7 @@
     };
 
     @Test
-    public void queryJSONcosmas17 () {
+    public void queryJSONcosmas17 () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/cosmas17.json").getFile());
 
 	// "#BED($wegen , +sa)"
@@ -257,7 +257,7 @@
     };
 
     @Test
-    public void queryJSONcosmas20 () {
+    public void queryJSONcosmas20 () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/cosmas20.json").getFile());
 
 	//     "MORPH(V) #IN(R) #ELEM(S)"
@@ -267,16 +267,15 @@
 
 
     @Test
-    public void queryJSONrepetition () {
+    public void queryJSONrepetition () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/bsp-repetition.jsonld").getFile());
 
 	// der[cnx/p=A]{0,2}[tt/p=NN]
-	assertEquals(sqwi.toQuery().toString(), "spanNext(spanOr([tokens:s:der, spanNext(tokens:s:der, spanRepetition(tokens:cnx/p:A{1,2}))]), tokens:tt/p:NN)");
+	assertEquals(sqwi.toQuery().toString(), "spanNext(tokens:s:der, spanOr([tokens:tt/p:NN, spanNext(spanRepetition(tokens:cnx/p:A{1,2}), tokens:tt/p:NN)]))");
     };
 
-
     @Test
-    public void queryJSONboundaryBug () {
+    public void queryJSONboundaryBug () throws QueryException {
 	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/bsp-boundary.jsonld").getFile());
 
 	// Tal []{1,} Wald
@@ -284,7 +283,75 @@
     };
 
 
+    @Test
+    public void queryJSONseqEmpty () throws QueryException {
+	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/sequence/empty.jsonld").getFile());
 
+	// []
+	assertTrue(sqwi.isEmpty());
+    };
+
+    @Test
+    public void queryJSONseqEmptyEnd () throws QueryException {
+	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/sequence/empty-last.jsonld").getFile());
+	assertEquals(sqwi.toQuery().toString(), "spanExpansion(tokens:s:der, []{1, 1}, right)");
+    };
+
+    @Test
+    public void queryJSONseqEmptyEndClass () throws QueryException {
+	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/sequence/empty-last-class.jsonld").getFile());
+	// der{3:[]}
+	assertEquals(sqwi.toQuery().toString(), "spanExpansion(tokens:s:der, []{1, 1}, right, class:3)");
+    };
+
+    @Test
+    public void queryJSONseqEmptyEndRepetition () throws QueryException {
+	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/sequence/empty-last-repetition.jsonld").getFile());
+	// der[]{3,5}
+	assertEquals(sqwi.toQuery().toString(), "spanExpansion(tokens:s:der, []{3, 5}, right)");
+    };
+
+    @Test
+    public void queryJSONseqEmptyStart () throws QueryException {
+	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/sequence/empty-first.jsonld").getFile());
+	// [][tt/p=NN]
+	assertEquals(sqwi.toQuery().toString(), "spanExpansion(tokens:tt/p:NN, []{1, 1}, left)");
+    };
+
+    @Test
+    public void queryJSONseqEmptyStartClass () throws QueryException {
+	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/sequence/empty-first-class.jsonld").getFile());
+	// {2:[]}[tt/p=NN]
+	assertEquals(sqwi.toQuery().toString(), "spanExpansion(tokens:tt/p:NN, []{1, 1}, left, class:2)");
+    };
+
+    @Test
+    public void queryJSONseqEmptyStartRepetition () throws QueryException {
+	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/sequence/empty-first-repetition.jsonld").getFile());
+	// []{2,7}[tt/p=NN]
+	assertEquals(sqwi.toQuery().toString(), "spanExpansion(tokens:tt/p:NN, []{2, 7}, left)");
+    };
+
+    @Test
+    public void queryJSONseqEmptyMiddle () throws QueryException {
+	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/sequence/empty-middle.jsonld").getFile());
+	// der[][tt/p=NN]
+	assertEquals(sqwi.toQuery().toString(), "spanNext(tokens:s:der, spanExpansion(tokens:tt/p:NN, []{1, 1}, left))");
+    };
+
+    @Test
+    public void queryJSONseqEmptyMiddleClass () throws QueryException {
+	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/sequence/empty-middle-class.jsonld").getFile());
+	// der{1:[]}[tt/p=NN]
+	assertEquals(sqwi.toQuery().toString(), "spanNext(tokens:s:der, spanExpansion(tokens:tt/p:NN, []{1, 1}, left, class:1))");
+    };
+
+    @Test
+    public void queryJSONseqEmptyMiddleRepetition () throws QueryException {
+	SpanQueryWrapper sqwi = jsonQuery(getClass().getResource("/queries/sequence/empty-middle-repetition.jsonld").getFile());
+	// der[]{4,8}[tt/p=NN]
+	assertEquals(sqwi.toQuery().toString(), "spanNext(tokens:s:der, spanExpansion(tokens:tt/p:NN, []{4, 8}, left))");
+    };
 
     public static String getString (String path) {
 	StringBuilder contentBuilder = new StringBuilder();
diff --git a/src/test/java/de/ids_mannheim/korap/query/TestSpanAlterQuery.java b/src/test/java/de/ids_mannheim/korap/query/TestSpanAlterQuery.java
index 95cc47b..9be1fcc 100644
--- a/src/test/java/de/ids_mannheim/korap/query/TestSpanAlterQuery.java
+++ b/src/test/java/de/ids_mannheim/korap/query/TestSpanAlterQuery.java
@@ -5,6 +5,8 @@
 import de.ids_mannheim.korap.query.wrap.SpanRegexQueryWrapper;
 import de.ids_mannheim.korap.query.wrap.SpanSegmentQueryWrapper;
 
+import de.ids_mannheim.korap.util.QueryException;
+
 import static org.junit.Assert.*;
 import org.junit.Test;
 import org.junit.Ignore;
@@ -12,9 +14,9 @@
 import org.junit.runners.JUnit4;
 
 @RunWith(JUnit4.class)
-public class TestSpanAlterQuery {
+public class TestSpanAlterQuery  {
     @Test
-    public void spanAlterQuery () {
+    public void spanAlterQuery () throws QueryException {
 
 	SpanAlterQueryWrapper ssaquery = new SpanAlterQueryWrapper("field");
 	ssaquery.or("b");
@@ -22,7 +24,7 @@
     };
 
     @Test
-    public void spanAlterQuery2 () {
+    public void spanAlterQuery2 () throws QueryException {
 
 	SpanAlterQueryWrapper ssaquery = new SpanAlterQueryWrapper("field");
 	ssaquery.or("b").or("c");
@@ -30,7 +32,7 @@
     };
 
     @Test
-    public void spanAlterQuery3 () {
+    public void spanAlterQuery3 () throws QueryException {
 	SpanAlterQueryWrapper ssaquery = new SpanAlterQueryWrapper("field");
 	ssaquery.or("b").or("c").or("d");
 	assertEquals("spanOr([field:b, field:c, field:d])", ssaquery.toQuery().toString());
@@ -38,7 +40,7 @@
 
 
     @Test
-    public void spanAlterQuery4 () {
+    public void spanAlterQuery4 () throws QueryException {
 	SpanSegmentQueryWrapper segquery = new SpanSegmentQueryWrapper("field", "a", "b", "c");
 	SpanAlterQueryWrapper ssaquery = new SpanAlterQueryWrapper("field");
 	ssaquery.or("d").or(segquery).or("e");
@@ -46,7 +48,7 @@
     };
 
     @Test
-    public void spanAlterQuery5 () {
+    public void spanAlterQuery5 () throws QueryException {
 	SpanRegexQueryWrapper srequery = new SpanRegexQueryWrapper("field", "a[bc]d.?e");
 	SpanAlterQueryWrapper ssaquery = new SpanAlterQueryWrapper("field");
 	ssaquery.or("f").or(srequery).or("g");
diff --git a/src/test/java/de/ids_mannheim/korap/query/TestSpanSegmentAlterQuery.java b/src/test/java/de/ids_mannheim/korap/query/TestSpanSegmentAlterQuery.java
index f0783b8..e0ea83a 100644
--- a/src/test/java/de/ids_mannheim/korap/query/TestSpanSegmentAlterQuery.java
+++ b/src/test/java/de/ids_mannheim/korap/query/TestSpanSegmentAlterQuery.java
@@ -5,6 +5,8 @@
 import de.ids_mannheim.korap.query.wrap.SpanRegexQueryWrapper;
 import de.ids_mannheim.korap.query.wrap.SpanSegmentQueryWrapper;
 
+import de.ids_mannheim.korap.util.QueryException;
+
 import static org.junit.Assert.*;
 import org.junit.Test;
 import org.junit.Ignore;
@@ -14,7 +16,7 @@
 @RunWith(JUnit4.class)
 public class TestSpanSegmentAlterQuery {
     @Test
-    public void spanAlterQuery () {
+    public void spanAlterQuery () throws QueryException {
 
 	SpanAlterQueryWrapper ssaquery = new SpanAlterQueryWrapper("field");
 	ssaquery.or("b");
@@ -22,7 +24,7 @@
     };
 
     @Test
-    public void spanAlterQuery2 () {
+    public void spanAlterQuery2 () throws QueryException {
 
 	SpanAlterQueryWrapper ssaquery = new SpanAlterQueryWrapper("field");
 	ssaquery.or("b").or("c");
@@ -30,7 +32,7 @@
     };
 
     @Test
-    public void spanAlterQuery3 () {
+    public void spanAlterQuery3 () throws QueryException {
 	SpanAlterQueryWrapper ssaquery = new SpanAlterQueryWrapper("field");
 	ssaquery.or("b").or("c").or("d");
 	assertEquals("spanOr([field:b, field:c, field:d])", ssaquery.toQuery().toString());
@@ -38,7 +40,7 @@
 
 
     @Test
-    public void spanAlterQuery4 () {
+    public void spanAlterQuery4 () throws QueryException {
 	SpanSegmentQueryWrapper segquery = new SpanSegmentQueryWrapper("field", "a", "b", "c");
 	SpanAlterQueryWrapper ssaquery = new SpanAlterQueryWrapper("field");
 	ssaquery.or("d").or(segquery).or("e");
@@ -46,7 +48,7 @@
     };
 
     @Test
-    public void spanAlterQuery5 () {
+    public void spanAlterQuery5 () throws QueryException {
 	SpanRegexQueryWrapper srequery = new SpanRegexQueryWrapper("field", "a[bc]d.?e");
 	SpanAlterQueryWrapper ssaquery = new SpanAlterQueryWrapper("field");
 	ssaquery.or("f").or(srequery).or("g");
diff --git a/src/test/java/de/ids_mannheim/korap/query/TestSpanSegmentQuery.java b/src/test/java/de/ids_mannheim/korap/query/TestSpanSegmentQuery.java
index e118c3c..444a188 100644
--- a/src/test/java/de/ids_mannheim/korap/query/TestSpanSegmentQuery.java
+++ b/src/test/java/de/ids_mannheim/korap/query/TestSpanSegmentQuery.java
@@ -5,6 +5,8 @@
 import de.ids_mannheim.korap.query.wrap.SpanRegexQueryWrapper;
 import de.ids_mannheim.korap.query.wrap.SpanAlterQueryWrapper;
 
+import de.ids_mannheim.korap.util.QueryException;
+
 import static org.junit.Assert.*;
 import org.junit.Test;
 import org.junit.Ignore;
@@ -14,7 +16,7 @@
 @RunWith(JUnit4.class)
 public class TestSpanSegmentQuery {
     @Test
-    public void spanSegmentQuery () {
+    public void spanSegmentQuery () throws QueryException {
 
 	SpanSegmentQueryWrapper ssquery = new SpanSegmentQueryWrapper("field","a");
 	assertEquals("field:a", ssquery.toQuery().toString());
@@ -27,7 +29,7 @@
     };
 
     @Test
-    public void spanSegmentQueryExclusive () {
+    public void spanSegmentQueryExclusive () throws QueryException {
 
 	SpanSegmentQueryWrapper ssquery = new SpanSegmentQueryWrapper("field","a");
 	assertEquals("field:a", ssquery.toQuery().toString());
@@ -44,7 +46,7 @@
 
 
     @Test
-    public void spanSegmentRegexQuery () {
+    public void spanSegmentRegexQuery () throws QueryException {
 	SpanSegmentQueryWrapper ssquery = new SpanSegmentQueryWrapper("field");
 	assertNull(ssquery.toQuery());
 	ssquery.with("a");
@@ -73,7 +75,7 @@
     };
 
     @Test
-    public void spanSegmentAlterQuery () {
+    public void spanSegmentAlterQuery () throws QueryException {
 	SpanSegmentQueryWrapper ssquery = new SpanSegmentQueryWrapper("field");
 	assertNull(ssquery.toQuery());
 
@@ -87,7 +89,7 @@
 
 
     @Test
-    public void spanSegmentCloneQuery () {
+    public void spanSegmentCloneQuery () throws QueryException {
 	SpanSegmentQueryWrapper ssquery = new SpanSegmentQueryWrapper("field", "a", "b");
 	assertEquals("spanSegment(field:a, field:b)", ssquery.toQuery().toString());
 
diff --git a/src/test/java/de/ids_mannheim/korap/query/TestSpanSegmentSequenceQuery.java b/src/test/java/de/ids_mannheim/korap/query/TestSpanSegmentSequenceQuery.java
index 5f70291..d93d402 100644
--- a/src/test/java/de/ids_mannheim/korap/query/TestSpanSegmentSequenceQuery.java
+++ b/src/test/java/de/ids_mannheim/korap/query/TestSpanSegmentSequenceQuery.java
@@ -6,6 +6,8 @@
 import de.ids_mannheim.korap.query.wrap.SpanAlterQueryWrapper;
 import de.ids_mannheim.korap.query.wrap.SpanSequenceQueryWrapper;
 
+import de.ids_mannheim.korap.util.QueryException;
+
 import static org.junit.Assert.*;
 import org.junit.Test;
 import org.junit.Ignore;
@@ -16,11 +18,11 @@
 public class TestSpanSegmentSequenceQuery {
 
     @Test
-    public void spanSegmentSequenceQuery () {
+    public void spanSegmentSequenceQuery () throws QueryException {
 	SpanSequenceQueryWrapper sssq = new SpanSequenceQueryWrapper("field");
 
 	assertNull(sssq.toQuery());
-
+ 
 	sssq.append("a").append("b");
 
 	assertEquals("spanNext(field:a, field:b)", sssq.toQuery().toString());
@@ -31,7 +33,7 @@
     };
 
     @Test
-    public void spanSegmentSequenceQuery2 () {
+    public void spanSegmentSequenceQuery2 () throws QueryException {
 	SpanSegmentQueryWrapper ssq = new SpanSegmentQueryWrapper("field", "-c", "-d", "-e");
 	SpanSequenceQueryWrapper sssq = new SpanSequenceQueryWrapper("field", "a", "b");
 
@@ -42,7 +44,7 @@
     };
 
     @Test
-    public void spanSegmentSequenceQuery3 () {
+    public void spanSegmentSequenceQuery3 () throws QueryException {
 	SpanSequenceQueryWrapper sssq = new SpanSequenceQueryWrapper("field", "a", "b");
 	SpanRegexQueryWrapper ssreq = new SpanRegexQueryWrapper("field", "c.?d");
 
@@ -52,7 +54,7 @@
     };
 
     @Test
-    public void spanSegmentSequenceQueryPrepend () {
+    public void spanSegmentSequenceQueryPrepend () throws QueryException {
 	SpanSequenceQueryWrapper sssq = new SpanSequenceQueryWrapper("field", "b", "c");
 
 	sssq.prepend("a");
@@ -61,7 +63,7 @@
     };
 
     @Test
-    public void spanSegmentSequenceQueryPrepend2 () {
+    public void spanSegmentSequenceQueryPrepend2 () throws QueryException {
 	SpanSequenceQueryWrapper sssq = new SpanSequenceQueryWrapper("field", "d", "e");
 	SpanSegmentQueryWrapper ssq = new SpanSegmentQueryWrapper("field", "-a", "-b", "-c");
 
@@ -71,7 +73,7 @@
     };
 
     @Test
-    public void spanSegmentSequenceQueryPrepend3 () {
+    public void spanSegmentSequenceQueryPrepend3 () throws QueryException {
 	SpanSequenceQueryWrapper sssq = new SpanSequenceQueryWrapper("field", "c", "d");
 	SpanRegexQueryWrapper ssreq = new SpanRegexQueryWrapper("field", "a.?b");
 
diff --git a/src/test/java/de/ids_mannheim/korap/query/TestSpanSequenceQuery.java b/src/test/java/de/ids_mannheim/korap/query/TestSpanSequenceQuery.java
index 0b3f884..f6fd664 100644
--- a/src/test/java/de/ids_mannheim/korap/query/TestSpanSequenceQuery.java
+++ b/src/test/java/de/ids_mannheim/korap/query/TestSpanSequenceQuery.java
@@ -3,6 +3,8 @@
 import java.util.*;
 import de.ids_mannheim.korap.query.wrap.SpanSequenceQueryWrapper;
 
+import de.ids_mannheim.korap.util.QueryException;
+
 import static org.junit.Assert.*;
 import org.junit.Test;
 import org.junit.Ignore;
@@ -13,7 +15,7 @@
 public class TestSpanSequenceQuery {
 
     @Test
-    public void spanSequenceQuery () {
+    public void spanSequenceQuery () throws QueryException {
 	SpanSequenceQueryWrapper sssq = new SpanSequenceQueryWrapper("field");
 	assertNull(sssq.toQuery());
 	assertFalse(sssq.hasConstraints());
diff --git a/src/test/java/de/ids_mannheim/korap/query/TestSpanWithinQuery.java b/src/test/java/de/ids_mannheim/korap/query/TestSpanWithinQuery.java
index 5a86815..c81fc79 100644
--- a/src/test/java/de/ids_mannheim/korap/query/TestSpanWithinQuery.java
+++ b/src/test/java/de/ids_mannheim/korap/query/TestSpanWithinQuery.java
@@ -4,6 +4,8 @@
 import de.ids_mannheim.korap.query.wrap.SpanSequenceQueryWrapper;
 import de.ids_mannheim.korap.query.SpanWithinQuery;
 
+import de.ids_mannheim.korap.util.QueryException;
+
 import static org.junit.Assert.*;
 import org.junit.Test;
 import org.junit.Ignore;
@@ -13,7 +15,7 @@
 @RunWith(JUnit4.class)
 public class TestSpanWithinQuery {
     @Test
-    public void spanSegmentWithinQuery () {
+    public void spanSegmentWithinQuery () throws QueryException {
 
 	SpanSequenceQueryWrapper ssquery = new SpanSequenceQueryWrapper("field", "a", "b", "c");
 	SpanWithinQuery ssequery = new SpanWithinQuery("s", ssquery.toQuery());
diff --git a/src/test/java/de/ids_mannheim/korap/search/TestKorapResult.java b/src/test/java/de/ids_mannheim/korap/search/TestKorapResult.java
index b99596c..a64a3e4 100644
--- a/src/test/java/de/ids_mannheim/korap/search/TestKorapResult.java
+++ b/src/test/java/de/ids_mannheim/korap/search/TestKorapResult.java
@@ -12,6 +12,8 @@
 import de.ids_mannheim.korap.KorapMatch;
 import de.ids_mannheim.korap.index.FieldDocument;
 
+import de.ids_mannheim.korap.util.QueryException;
+
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.JsonNode;
 
@@ -27,7 +29,7 @@
 public class TestKorapResult {
 
     @Test
-    public void checkJSONResult () throws IOException  {
+    public void checkJSONResult () throws Exception  {
 	KorapIndex ki = new KorapIndex();
 	FieldDocument fd = new FieldDocument();
 	fd.addString("ID", "doc-1");
@@ -93,7 +95,7 @@
     };
 
     @Test
-    public void checkJSONResultForJSONInput () throws IOException  {
+    public void checkJSONResultForJSONInput () throws Exception  {
 	KorapIndex ki = new KorapIndex();
 	FieldDocument fd = new FieldDocument();
 	fd.addString("ID", "doc-1");
diff --git a/src/test/resources/queries/sequence/empty-first-class.jsonld b/src/test/resources/queries/sequence/empty-first-class.jsonld
new file mode 100644
index 0000000..89f44e3
--- /dev/null
+++ b/src/test/resources/queries/sequence/empty-first-class.jsonld
@@ -0,0 +1,39 @@
+{
+   "@context" : "http://ids-mannheim.de/ns/KorAP/json-ld/v0.1/context.jsonld",
+   "collections" : [
+      {
+         "@type" : "korap:meta-filter",
+         "@value" : {
+            "@field" : "korap:field#corpusID",
+            "@type" : "korap:term",
+            "@value" : "WPD"
+         }
+      }
+   ],
+   "meta" : {},
+   "query" : {
+      "@type" : "korap:group",
+      "operands" : [
+	 {
+	     "@type" : "korap:group",
+	     "class" : 2,
+	     "operation" : "operation:class",
+	     "operands" : [
+             {
+               "@type" : "korap:token"
+             }]
+         },
+         {
+            "@type" : "korap:token",
+            "wrap" : {
+               "@type" : "korap:term",
+               "foundry" : "tt",
+               "key" : "NN",
+               "layer" : "p",
+               "match" : "match:eq"
+            }
+         }
+      ],
+      "operation" : "operation:sequence"
+   }
+}
\ No newline at end of file
diff --git a/src/test/resources/queries/sequence/empty-first-repetition.jsonld b/src/test/resources/queries/sequence/empty-first-repetition.jsonld
new file mode 100644
index 0000000..91c09ad
--- /dev/null
+++ b/src/test/resources/queries/sequence/empty-first-repetition.jsonld
@@ -0,0 +1,43 @@
+{
+   "@context" : "http://ids-mannheim.de/ns/KorAP/json-ld/v0.1/context.jsonld",
+   "collections" : [
+      {
+         "@type" : "korap:meta-filter",
+         "@value" : {
+            "@field" : "korap:field#corpusID",
+            "@type" : "korap:term",
+            "@value" : "WPD"
+         }
+      }
+   ],
+   "meta" : {},
+   "query" : {
+      "@type" : "korap:group",
+     "operands" : [
+       {
+	 "@type" : "korap:group",
+	 "operation" : "operation:repetition",
+	 "boundary": {
+	   "@type" : "korap:boundary",
+	   "min" : 2,
+	   "max" : 7
+	 },
+	 "operands" : [
+	   {
+             "@type" : "korap:token"
+	   }]	     
+         },
+         {
+            "@type" : "korap:token",
+            "wrap" : {
+               "@type" : "korap:term",
+               "foundry" : "tt",
+               "key" : "NN",
+               "layer" : "p",
+               "match" : "match:eq"
+            }
+         }
+      ],
+      "operation" : "operation:sequence"
+   }
+}
diff --git a/src/test/resources/queries/sequence/empty-first.jsonld b/src/test/resources/queries/sequence/empty-first.jsonld
new file mode 100644
index 0000000..0c7b7a5
--- /dev/null
+++ b/src/test/resources/queries/sequence/empty-first.jsonld
@@ -0,0 +1,33 @@
+{
+   "@context" : "http://ids-mannheim.de/ns/KorAP/json-ld/v0.1/context.jsonld",
+   "collections" : [
+      {
+         "@type" : "korap:meta-filter",
+         "@value" : {
+            "@field" : "korap:field#corpusID",
+            "@type" : "korap:term",
+            "@value" : "WPD"
+         }
+      }
+   ],
+   "meta" : {},
+   "query" : {
+      "@type" : "korap:group",
+      "operands" : [
+	 {
+             "@type" : "korap:token"
+         },
+         {
+            "@type" : "korap:token",
+            "wrap" : {
+               "@type" : "korap:term",
+               "foundry" : "tt",
+               "key" : "NN",
+               "layer" : "p",
+               "match" : "match:eq"
+            }
+         }
+      ],
+      "operation" : "operation:sequence"
+   }
+}
\ No newline at end of file
diff --git a/src/test/resources/queries/sequence/empty-last-class.jsonld b/src/test/resources/queries/sequence/empty-last-class.jsonld
new file mode 100644
index 0000000..e2591e7
--- /dev/null
+++ b/src/test/resources/queries/sequence/empty-last-class.jsonld
@@ -0,0 +1,38 @@
+{
+   "@context" : "http://ids-mannheim.de/ns/KorAP/json-ld/v0.1/context.jsonld",
+   "collections" : [
+      {
+         "@type" : "korap:meta-filter",
+         "@value" : {
+            "@field" : "korap:field#corpusID",
+            "@type" : "korap:term",
+            "@value" : "WPD"
+         }
+      }
+   ],
+   "meta" : {},
+   "query" : {
+      "@type" : "korap:group",
+      "operands" : [
+         {
+            "@type" : "korap:token",
+            "wrap" : {
+               "@type" : "korap:term",
+               "key" : "der",
+               "layer" : "orth",
+               "match" : "match:eq"
+            }
+         },
+	 {
+	     "@type" : "korap:group",
+	     "class" : 3,
+	     "operation" : "operation:class",
+	     "operands" : [
+             {
+             "@type" : "korap:token"
+	     }]
+         }
+      ],
+      "operation" : "operation:sequence"
+   }
+}
\ No newline at end of file
diff --git a/src/test/resources/queries/sequence/empty-last-repetition.jsonld b/src/test/resources/queries/sequence/empty-last-repetition.jsonld
new file mode 100644
index 0000000..c57d45a
--- /dev/null
+++ b/src/test/resources/queries/sequence/empty-last-repetition.jsonld
@@ -0,0 +1,43 @@
+{
+  "@context" : "http://ids-mannheim.de/ns/KorAP/json-ld/v0.1/context.jsonld",
+  "collections" : [
+    {
+      "@type" : "korap:meta-filter",
+      "@value" : {
+        "@field" : "korap:field#corpusID",
+        "@type" : "korap:term",
+        "@value" : "WPD"
+      }
+    }
+  ],
+  "meta" : {},
+  "query" : {
+    "@type" : "korap:group",
+    "operands" : [
+      {
+        "@type" : "korap:token",
+        "wrap" : {
+          "@type" : "korap:term",
+          "key" : "der",
+          "layer" : "orth",
+          "match" : "match:eq"
+        }
+      },
+      {
+	"@type" : "korap:group",
+	"operation" : "operation:repetition",
+	"boundary": {
+	  "@type" : "korap:boundary",
+	  "min" : 3,
+	  "max" : 5
+	},
+	"operands" : [
+	  {
+            "@type" : "korap:token"
+	  }
+	]
+      }
+    ],
+    "operation" : "operation:sequence"
+  }
+}
diff --git a/src/test/resources/queries/sequence/empty-last.jsonld b/src/test/resources/queries/sequence/empty-last.jsonld
new file mode 100644
index 0000000..395e8f8
--- /dev/null
+++ b/src/test/resources/queries/sequence/empty-last.jsonld
@@ -0,0 +1,32 @@
+{
+   "@context" : "http://ids-mannheim.de/ns/KorAP/json-ld/v0.1/context.jsonld",
+   "collections" : [
+      {
+         "@type" : "korap:meta-filter",
+         "@value" : {
+            "@field" : "korap:field#corpusID",
+            "@type" : "korap:term",
+            "@value" : "WPD"
+         }
+      }
+   ],
+   "meta" : {},
+   "query" : {
+      "@type" : "korap:group",
+      "operands" : [
+         {
+            "@type" : "korap:token",
+            "wrap" : {
+               "@type" : "korap:term",
+               "key" : "der",
+               "layer" : "orth",
+               "match" : "match:eq"
+            }
+         },
+	 {
+             "@type" : "korap:token"
+         }
+      ],
+      "operation" : "operation:sequence"
+   }
+}
\ No newline at end of file
diff --git a/src/test/resources/queries/sequence/empty-middle-class.jsonld b/src/test/resources/queries/sequence/empty-middle-class.jsonld
new file mode 100644
index 0000000..865bfa1
--- /dev/null
+++ b/src/test/resources/queries/sequence/empty-middle-class.jsonld
@@ -0,0 +1,49 @@
+{
+   "@context" : "http://ids-mannheim.de/ns/KorAP/json-ld/v0.1/context.jsonld",
+   "collections" : [
+      {
+         "@type" : "korap:meta-filter",
+         "@value" : {
+            "@field" : "korap:field#corpusID",
+            "@type" : "korap:term",
+            "@value" : "WPD"
+         }
+      }
+   ],
+   "meta" : {},
+   "query" : {
+      "@type" : "korap:group",
+      "operands" : [
+         {
+            "@type" : "korap:token",
+            "wrap" : {
+               "@type" : "korap:term",
+               "key" : "der",
+               "layer" : "orth",
+               "match" : "match:eq"
+            }
+         },
+	 {
+	     "@type" : "korap:group",
+	     "class" : 1,
+	     "operation" : "operation:class",
+	     "operands" : [
+	 	 {
+         	     "@type" : "korap:token"
+         	 }
+             ]
+         },
+         {
+            "@type" : "korap:token",
+            "wrap" : {
+               "@type" : "korap:term",
+               "foundry" : "tt",
+               "key" : "NN",
+               "layer" : "p",
+               "match" : "match:eq"
+            }
+         }
+      ],
+      "operation" : "operation:sequence"
+   }
+}
\ No newline at end of file
diff --git a/src/test/resources/queries/sequence/empty-middle-repetition.jsonld b/src/test/resources/queries/sequence/empty-middle-repetition.jsonld
new file mode 100644
index 0000000..22677c5
--- /dev/null
+++ b/src/test/resources/queries/sequence/empty-middle-repetition.jsonld
@@ -0,0 +1,52 @@
+{
+   "@context" : "http://ids-mannheim.de/ns/KorAP/json-ld/v0.1/context.jsonld",
+   "collections" : [
+      {
+         "@type" : "korap:meta-filter",
+         "@value" : {
+            "@field" : "korap:field#corpusID",
+            "@type" : "korap:term",
+            "@value" : "WPD"
+         }
+      }
+   ],
+   "meta" : {},
+   "query" : {
+      "@type" : "korap:group",
+      "operands" : [
+         {
+            "@type" : "korap:token",
+            "wrap" : {
+               "@type" : "korap:term",
+               "key" : "der",
+               "layer" : "orth",
+               "match" : "match:eq"
+            }
+         },
+	 {
+	 "@type" : "korap:group",
+	 "operation" : "operation:repetition",
+	 "boundary": {
+	   "@type" : "korap:boundary",
+	   "min" : 4,
+	   "max" : 8
+	 },
+	 "operands" : [
+	   {
+             "@type" : "korap:token"
+	     }]	     
+         },
+         {
+            "@type" : "korap:token",
+            "wrap" : {
+               "@type" : "korap:term",
+               "foundry" : "tt",
+               "key" : "NN",
+               "layer" : "p",
+               "match" : "match:eq"
+            }
+         }
+      ],
+      "operation" : "operation:sequence"
+   }
+}
\ No newline at end of file
diff --git a/src/test/resources/queries/sequence/empty-middle.jsonld b/src/test/resources/queries/sequence/empty-middle.jsonld
new file mode 100644
index 0000000..005bae4
--- /dev/null
+++ b/src/test/resources/queries/sequence/empty-middle.jsonld
@@ -0,0 +1,42 @@
+{
+   "@context" : "http://ids-mannheim.de/ns/KorAP/json-ld/v0.1/context.jsonld",
+   "collections" : [
+      {
+         "@type" : "korap:meta-filter",
+         "@value" : {
+            "@field" : "korap:field#corpusID",
+            "@type" : "korap:term",
+            "@value" : "WPD"
+         }
+      }
+   ],
+   "meta" : {},
+   "query" : {
+      "@type" : "korap:group",
+      "operands" : [
+         {
+            "@type" : "korap:token",
+            "wrap" : {
+               "@type" : "korap:term",
+               "key" : "der",
+               "layer" : "orth",
+               "match" : "match:eq"
+            }
+         },
+	 {
+             "@type" : "korap:token"
+         },
+         {
+            "@type" : "korap:token",
+            "wrap" : {
+               "@type" : "korap:term",
+               "foundry" : "tt",
+               "key" : "NN",
+               "layer" : "p",
+               "match" : "match:eq"
+            }
+         }
+      ],
+      "operation" : "operation:sequence"
+   }
+}
\ No newline at end of file
diff --git a/src/test/resources/queries/sequence/empty.jsonld b/src/test/resources/queries/sequence/empty.jsonld
new file mode 100644
index 0000000..473404d
--- /dev/null
+++ b/src/test/resources/queries/sequence/empty.jsonld
@@ -0,0 +1,17 @@
+{
+   "@context" : "http://ids-mannheim.de/ns/KorAP/json-ld/v0.1/context.jsonld",
+   "collections" : [
+      {
+         "@type" : "korap:meta-filter",
+         "@value" : {
+            "@field" : "korap:field#corpusID",
+            "@type" : "korap:term",
+            "@value" : "WPD"
+         }
+      }
+   ],
+   "meta" : {},
+   "query" : {
+     "@type" : "korap:token"
+   }
+}
\ No newline at end of file