- implemented position and spanclass operators in PoliqarpPlusTree
- changed 'within(x,y)' operator to 'contains(x,y)' in order to avoid name conflict with PQ-native 'within' 
diff --git a/src/main/java/de/ids_mannheim/korap/query/serialize/PoliqarpPlusTree.java b/src/main/java/de/ids_mannheim/korap/query/serialize/PoliqarpPlusTree.java
index ff6fe90..20a37e7 100644
--- a/src/main/java/de/ids_mannheim/korap/query/serialize/PoliqarpPlusTree.java
+++ b/src/main/java/de/ids_mannheim/korap/query/serialize/PoliqarpPlusTree.java
@@ -76,11 +76,15 @@
 	/**
 	 * Marks the currently active object (sequence/token/group...) in order to know where to add stuff like occurrence info etc.
 	 */
-	LinkedHashMap<String,Object> curObject = new LinkedHashMap<String,Object>();
+//	LinkedHashMap<String,Object> curObject = new LinkedHashMap<String,Object>();
 	/**
 	 * Marks the currently active token in order to know where to add flags (might already have been taken away from token stack).
 	 */
 	LinkedHashMap<String,Object> curToken = new LinkedHashMap<String,Object>();
+	/**
+	 * Keeps track of active object.
+	 */
+	LinkedList<Object> objectStack = new LinkedList<Object>();
 	
 	/**
 	 * 
@@ -142,6 +146,7 @@
 		openNodeCats.push(nodeCat);
 		
 //		System.out.println(openNodeCats);
+		
 
 		/*
 		 ****************************************************************
@@ -156,29 +161,37 @@
 		// cq_segments/sq_segments: token group
 		if (nodeCat.equals("cq_segments") || nodeCat.equals("sq_segments")) {
 			// disregard empty segments in simple queries (parsed by ANTLR as empty cq_segments) 
-			ignoreCq_segment = (node.getChildCount() == 1 && node.getChild(0).toStringTree(poliqarpParser).equals(" ") && getNodeCat(node.getChild(0)).equals("spanclass"));
-//			ignoreCq_segment = (node.getChildCount() == 1 && node.getChild(0).toStringTree(poliqarpParser).equals(" ") );
+			ignoreCq_segment = (node.getChildCount() == 1 && (node.getChild(0).toStringTree(poliqarpParser).equals(" ") || getNodeCat(node.getChild(0)).equals("spanclass") || getNodeCat(node.getChild(0)).equals("position")));
+//			ignoreCq_segment = (node.getChildCount() == 1 && node.getChild(0).toStringTree(poliqarpParser).equals(" ") && getNodeCat(node.getChild(0)).equals("spanclass") );
 			if (!ignoreCq_segment) {
 				LinkedHashMap<String,Object> sequence = new LinkedHashMap<String,Object>();
-				curObject = sequence;
+//				curObject = sequence;
+				objectStack.push(sequence);
 				// Step I: decide type of element (one or more elements? -> token or sequence)
 				if (node.getChildCount()>1) {
 					sequence.put("@type", "korap:sequence");
 					ArrayList<Object> sequenceOperands = new ArrayList<Object>();
 					sequence.put("operands", sequenceOperands);
 				} else {
-					// if only child, make the sequence a mere korap:token
-					sequence.put("@type", "korap:token");
+					if (openNodeCats.get(1).equals("position") || openNodeCats.get(1).equals("spanclass")) {
+						sequence.put("@type", "korap:group");
+					} else {
+						// if only child, make the sequence a mere korap:token
+						sequence.put("@type", "korap:token");
+					}
 					tokenStack.push(sequence);
 				}
 				// Step II: decide where to put this element (top query node or embedded in super sequence?)
+//				System.out.println(openNodeCats);
 				if (openNodeCats.get(1).equals("query")) {
+					// top query node
 					requestMap.put("query", sequence);
 				} else if (!groupStack.isEmpty()) {
-					groupStack.getFirst().add(sequence);
-				} else if (openNodeCats.get(1).equals("spanclass")) {
-					System.out.println("TODO!");
+					// embed in super group
+					ArrayList<Object> topGroupOperands = (ArrayList<Object>) groupStack.getFirst();
+					topGroupOperands.add(sequence);
 				} else if (!sequenceStack.isEmpty()){
+					// embed in super sequence
 					ArrayList<Object> topSequenceOperands = (ArrayList<Object>) sequenceStack.getFirst().get("operands");
 					topSequenceOperands.add(sequence);
 				}
@@ -197,8 +210,9 @@
 				// in case cq_segments has already added the token
 				token = tokenStack.getFirst();
 			}
-			curObject = token;
+//			curObject = token;
 			curToken = token;
+			objectStack.push(token);
 			
 			// Step II: start filling object and add to containing sequence
 			token.put("@type", "korap:token");
@@ -212,7 +226,8 @@
 		// disjoint cq_segments, like ([base=foo][base=bar])|[base=foobar]
 		if (nodeCat.equals("cq_disj_segments")) {
 			LinkedHashMap<String,Object> disjunction = new LinkedHashMap<String,Object>();
-			curObject = disjunction;
+//			curObject = disjunction;
+			objectStack.push(disjunction);
 			ArrayList<Object> disjOperands = new ArrayList<Object>();
 			disjunction.put("@type", "korap:group");
 			disjunction.put("relation", "or");
@@ -304,8 +319,9 @@
 				// in case sq_segments has already added the token
 				token = tokenStack.getFirst();
 			}
-			curObject = token;
+//			curObject = token;
 			curToken = token;
+			objectStack.push(token);
 			// Step II: fill object (token values) and put into containing sequence
 			token.put("@type", "korap:token");
 			String word = node.getChild(0).toStringTree(poliqarpParser);
@@ -330,23 +346,24 @@
 				// in case sq_segments has already added the token
 				elem = tokenStack.getFirst();
 			}
-			curObject = elem;
+//			curObject = elem;
 			curToken = elem;
+			objectStack.push(elem);
 			// Step II: fill object (token values) and put into containing sequence
 			elem.put("@type", "korap:element");
 			String value = node.getChild(1).toStringTree(poliqarpParser);
 			elem.put("@value", value);
-			
 			// add token to sequence only if it is not an only child (in that case, cq_segments has already added the info and is just waiting for the values from "field")
-//			if (node.getParent().getChildCount()>1) {
+			if (node.getParent().getChildCount()>1) {
 				ArrayList<Object> topSequenceOperands = (ArrayList<Object>) sequenceStack.getFirst().get("operands");
 				topSequenceOperands.add(elem);
-//			}
+			}
 		}
 		
 		if (nodeCat.equals("spanclass")) {
 			LinkedHashMap<String,Object> span = new LinkedHashMap<String,Object>();
-			curObject = span;
+//			curObject = span;
+			objectStack.push(span);
 			ArrayList<Object> spanOperands = new ArrayList<Object>();
 			String id = "0";
 			// Step I: get info
@@ -358,27 +375,46 @@
 					id = "0";
 				}
 			}
-			
 			span.put("@type", "korap:group");
 			span.put("class", id);
 			span.put("operands", spanOperands);
 			groupStack.push(spanOperands);
 			
-			// decide where to put the span
-			// add token to sequence only if it is not an only child (in that case, sq_segments has already added the info and is just waiting for the values from "field")
+			// Step II: decide where to put the span
+			// add span to sequence only if it is not an only child (in that case, sq_segments has already added the info and is just waiting for the relevant info)
 			if (node.getParent().getChildCount()>1) {
 				ArrayList<Object> topSequenceOperands = (ArrayList<Object>) sequenceStack.getFirst().get("operands");
 				topSequenceOperands.add(span);
 			} else if (openNodeCats.get(2).equals("query")) {
 				requestMap.put("query", span);	
-			} else if (!groupStack.isEmpty()) {
-				groupStack.getFirst().add(span);
+			} else if (groupStack.size()>1) {
+				groupStack.get(1).add(span);
 			} 
 			
 		}
 		
 		if (nodeCat.equals("position")) {
-			//TODO
+			LinkedHashMap<String,Object> positionGroup = new LinkedHashMap<String,Object>();
+//			curObject = positionGroup;
+			objectStack.push(positionGroup);
+			ArrayList<Object> posOperands = new ArrayList<Object>();
+			// Step I: get info
+			String relation = getNodeCat(node.getChild(0));
+			positionGroup.put("@type", "korap:group");
+			positionGroup.put("relation", relation.toLowerCase());
+			positionGroup.put("operands", posOperands);
+			groupStack.push(posOperands);
+			
+			// Step II: decide where to put the group
+			// add group to sequence only if it is not an only child (in that case, sq_segments has already added the info and is just waiting for the relevant info)
+			if (node.getParent().getChildCount()>1) {
+				ArrayList<Object> topSequenceOperands = (ArrayList<Object>) sequenceStack.getFirst().get("operands");
+				topSequenceOperands.add(positionGroup);
+			} else if (openNodeCats.get(2).equals("query")) {
+				requestMap.put("query", positionGroup);	
+			} else if (groupStack.size()>1) {
+				groupStack.get(1).add(positionGroup);
+			} 
 		}
 		
 		if (nodeCat.equals("shrink") || nodeCat.equals("split")) {
@@ -389,6 +425,8 @@
 		if (nodeCat.equals("occ")) {
 			ParseTree occChild = node.getChild(0);
 			String repetition = occChild.toStringTree(poliqarpParser);
+//			curObject.put("repetition", repetition);
+			LinkedHashMap<String,Object> curObject = (LinkedHashMap<String, Object>) objectStack.getFirst();
 			curObject.put("repetition", repetition);
 			visited.add(occChild);
 		}
@@ -413,12 +451,14 @@
 			ParseTree domainNode = node.getChild(2);
 			String domain = getNodeCat(domainNode);
 //			queryOperands.add("within:"+domain);
+			LinkedHashMap<String,Object> curObject = (LinkedHashMap<String, Object>) objectStack.getFirst();
 			curObject.put("within", domain);
 			visited.add(node.getChild(0));
 			visited.add(node.getChild(1));
 			visited.add(domainNode);
 		}
 		
+//		System.out.println(">>> "+requestMap.get("query")+" <<<");
 		/*
 		 ****************************************************************
 		 **************************************************************** 
@@ -434,23 +474,32 @@
 		// Stuff that happens when leaving a node (taking it off the stack)
 		if (nodeCat.equals("cq_segments") || nodeCat.equals("sq_segments")) {
 			// exclude whitespaces analysed as empty cq_segments
-			if (!ignoreCq_segment) {
+			if (!ignoreCq_segment && !sequenceStack.isEmpty()) {
+//			if (!ignoreCq_segment) {	
 				sequenceStack.pop();
+				objectStack.pop();
 			}
 		}
 		
 		if (nodeCat.equals("cq_disj_segments")) {
 			groupStack.pop();
+			objectStack.pop();
 		}
 		
 		if (nodeCat.equals("cq_segment") || nodeCat.equals("sq_segment")){
 			tokenStack.pop();
+			objectStack.pop();
 		}
 		
 		if (nodeCat.equals("conj_field")) {
 			fieldStack.pop();
 		}
 		
+		if (nodeCat.equals("position") || nodeCat.equals("spanclass")) {
+			groupStack.pop();
+			objectStack.pop();
+		}
+		
 		openNodeCats.pop();
 		
 	}
@@ -505,20 +554,24 @@
 		 * For testing
 		 */
 		String[] queries = new String[] {
-//				"[base=foo]|([base=foo][base=bar])*",
-//				"([base=foo]|[base=bar])[base=foobar]",
-//				"[base=foo]([base=bar]|[base=foobar/i])",
-//				"[base=bar|base=foo]",
-//				"[base=bar]",
-//				"[base=foo][base=bar]",
-//				"[(base=bar|base=foo)&orth=wee]",
-//				"[base=foo/i][base=bar]{2,4}",
-//				"foo bar/i"
+				"[base=foo]|([base=foo][base=bar])*",
+				"([base=foo]|[base=bar])[base=foobar]",
+				"[base=foo]([base=bar]|[base=foobar/i])",
+				"[base=bar|base=foo]",
+				"[base=bar]",
+				"[base=foo][base=bar]",
+				"[(base=bar|base=foo)&orth=wee]",
+				"[base=foo/i][base=bar]{2,4}",
+				"foo bar/i",
 				"{[base=foo]}[orth=bar]",
 				"{[base=foo]}{[orth=bar]}",
 				"{1:[base=foo]<np>}",
 				"shrink({[base=foo]}[orth=bar])",
-//				"[base=foo]|([base=foo][base=bar])* meta author=Goethe&year=1815"
+				"<np>",
+				"startsWith({<sentence>},<np>)",
+				"startsWith({<sentence>},[base=foo])",
+				"[base=foo]|([base=foo][base=bar])* meta author=Goethe&year=1815",
+				"([base=foo][base=bar])*",
 				};
 		for (String q : queries) {
 			try {